找回密码
 立即注册
查看: 2507|回复: 0
打印 上一主题 下一主题

phpcms v9 2013-02-01 会员中心注入漏洞分析报告

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告0 z8 w/ e& b2 Z/ Y# `
漏洞作者:skysheep5 D- x) G% S9 l0 p& H+ X; {+ J; |
分析作者:Seay$ L. n* ~' Z1 o6 O$ K
博客:http://www.cnseay.com/
; H1 B) V0 ]6 g9 b漏洞分析:
( F1 C, }* {9 g) p/ E  S( o; m  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。) \! y- O6 j2 m2 @

# s; X$ _+ X2 }: f0 y' F) K" h% j$ B+ l8 ~! v0 d4 R

: e. w6 E( E1 z5 a7 ?& Lpublic function account_manage_info() {  
- r" i& T, S+ q6 b0 L       if(isset($_POST['dosubmit'])) {  
* W( `9 \! r, E% D6 o- P5 _, d) N           //更新用户昵称  , Y. n. I' S% n+ U8 v' b0 S: @
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
1 w; p+ x. g/ q" O& D           if($nickname) {  
4 Y  B4 w  Z! Q' y  m              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  9 o) o2 h: d# D# C8 J
              if(!isset($cookietime)) {  
% r5 Z( {# A6 T/ u7 B                  $get_cookietime = param::get_cookie('cookietime');  
" B/ e' [  u  v              }  
+ O4 e$ O, V& _: f0 m              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
/ p' O4 N: P* \$ M7 r* m              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
& b8 I  V. i! p. n              param::set_cookie('_nickname', $nickname, $cookietime);  
  i* |+ z) `  a# n' f           }  2 Q. k) B- u9 w6 R5 t( C. H* k0 f  w- C
           require_once CACHE_MODEL_PATH.'member_input.class.php';  & Y8 R" s7 G6 a" J+ C
           require_once CACHE_MODEL_PATH.'member_update.class.php';  * Y' K# {( O/ A/ |$ Y1 Q+ V
           $member_input = new member_input($this->memberinfo['modelid']);  2 J  X+ X9 d* d8 _8 w
           $modelinfo = $member_input->get($_POST['info']);  
) n9 b0 P  z4 A6 S           $this->db->set_model($this->memberinfo['modelid']);  * v, T, h" u) u
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  * }8 \' l) I3 H0 Z( H
           if(!empty($membermodelinfo)) {  
& F1 u; e! |1 V              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
4 J. q9 A9 S/ t% c5 E+ g           } else {  
7 l) N/ n9 `  T' y" o              $modelinfo['userid'] = $this->memberinfo['userid'];  - j3 g. j' B: f5 g+ M
              $this->db->insert($modelinfo);  
. B& k# t7 z5 u" D           } ) \1 Y/ W4 m! z7 F' a" Q% ~9 q' ~
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,& a( @# t( U+ w/ J9 l9 V
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
( m* o2 S2 N/ O7 O
2 ^2 R& n; T% R9 P% h: q
" s3 ?5 Z. `1 _& E
9 i5 m1 F& b9 R  H. Qfunction get($data) {  + t% X+ [: S& F0 e: [
       $this->data = $data = trim_script($data);  
, `9 s! w% \* y8 w5 \       $model_cache = getcache('member_model', 'commons');  * l* J; ]6 J# _; K. j# |
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
+ @  o$ W$ ?5 x/ s$ J9 Y' a       $info = array();  
3 m" y" e; [. ?       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
; K7 e: n- f, D/ t5 }, m       if(is_array($data)) {  * b4 G, \2 P' `- y9 \! f
           foreach($data as $field=>$value) {  2 S0 I( G/ Q3 E1 P
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  + A4 ~# }3 z" |& N: I
              $name = $this->fields[$field]['name'];  
& |$ r/ J: G3 N& N              $minlength = $this->fields[$field]['minlength'];  
  i, x9 A4 Y- G, A3 A8 y              $maxlength = $this->fields[$field]['maxlength'];  % L+ q4 N7 h) O+ x) W  I% P- l/ C
              $pattern = $this->fields[$field]['pattern'];  
5 _6 o+ x* |3 d: B              $errortips = $this->fields[$field]['errortips'];  + v  q1 O' V9 B5 N
              if(empty($errortips)) $errortips = "$name 不符合要求!";  - a3 r3 a  W  J6 d" v- y' ^
              $length = empty($value) ? 0 : strlen($value);  : y% ]% k  {+ Z" x
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  . X+ m8 G2 }/ p- N( I8 N6 b, Q, o
              if($maxlength && $length > $maxlength && !$isimport) {  : A6 a1 ~5 x1 p/ y; |1 `  h
                  showmessage("$name 不得超过 $maxlength 个字符!");  
2 c0 a; n' O6 n) l* z. M  _' C              } else {  5 C2 Q5 a. `( J) ~( j
                  str_cut($value, $maxlength);  ' r4 a9 q6 ]# O/ k1 i
              }  
0 ^; N" j6 Y4 [+ r& `              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  : ]4 `# ^& t0 m9 m% z: N6 [
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
8 T) i, [( T1 [7 ^: P% _              $func = $this->fields[$field]['formtype'];  
; M, k! [# T- O5 B" U( P0 \7 ]) `              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
$ d( e4 P# m3 z              $info[$field] = $value;  
  x, p$ y' g9 A9 N& f9 J, w2 |           }  : M" G7 o/ t# i7 z' J: y- `: ]2 M$ {
       }  
# m" f& Z& T& U+ k       return $info;  
! q" n2 {5 V8 Z+ I2 w    } % M2 G% n- B5 k! P: o+ e
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,5 j# y7 x7 Q6 x( H! z  X
+ [& B/ C  D( K" S4 i6 ~9 }
再到phpcms\modules\member\index.php 文件account_manage_info函数! h: P2 {0 N- T. R) ^/ o
过了get()函数之后。
1 M3 R5 v+ W: y7 R7 o+ \! M7 S
; k  Z$ Z0 x0 _
8 m3 ~& v& D% ?) {$modelinfo = $member_input->get($_POST['info']);  + K& \$ P3 t$ \8 Z4 v6 I
           $this->db->set_model($this->memberinfo['modelid']);  4 P2 i9 ^; x1 N' d
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  8 l+ a! b7 l) j" m8 ]
           if(!empty($membermodelinfo)) {  
5 c# ~6 \2 |6 b, u              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  2 a7 B% A% d9 n. h% K+ c; x* b5 l
           } else {
) T, _! L4 m7 Z直接带入数据库,update函数我们跟进看看
/ _" F5 N! G+ O
( L& ?& v" K: S- C0 g+ H
) e7 \+ j; t- o" opublic function update($data, $table, $where = '') {  
. }% d5 y. x% m4 J       if($table == '' or $where == '') {  
) I- ~2 b7 p. _$ n: W$ a5 u0 j' n           return false;  
9 I9 C. Z$ u3 R4 ~6 @5 [       }  
5 z0 G6 q  F+ J' s& g' V8 V) l: J       $where = ' WHERE '.$where;  " ^1 K' D" }& e1 W* I* {& ^
       $field = '';  9 P1 n' ^3 N# i. [( M: U, Q
       if(is_string($data) && $data != '') {  5 j3 |0 J0 Y4 V; B- d; s! {8 }8 v
           $field = $data;  ! r# s. B" Y# U. `' v
       } elseif (is_array($data) && count($data) > 0) {  % j; Z  u& ]/ L& p0 v$ t
           $fields = array();  - g. B6 }* Z! B1 P' G
           foreach($data as $k=>$v) {  " V. k1 ?! s2 b4 R
              switch (substr($v, 0, 2)) {  ) N  }, _# l3 L+ {" I/ j6 L
                  case '+=':  
9 X& r9 `5 ?$ F& P* r+ K: ~                     $v = substr($v,2);  9 y2 s$ ^3 F* O1 Y4 K/ v. S* D  }
                     if (is_numeric($v)) {    K( r7 a0 r( C. G
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  1 F+ t, g' c1 E) j( t! Q7 s# W
                     } else {  1 L# q+ T$ P0 W7 c
                         continue;  4 R' s. X7 U' G  n2 Q7 k9 j$ P" q
                     }  
2 O8 V2 ]5 G* }9 O' v                     break;  
) r- \7 p, ]+ h/ l2 |/ |                  case '-=':  
7 u" |0 H% }. o3 ?7 a0 y& k                     $v = substr($v,2);  
! q7 M! o+ ^! ^2 O0 O, u6 [- ?/ Z                     if (is_numeric($v)) {  
9 a, {7 |  Y% W$ R' L                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
- i/ D  {! |( s                     } else {  ' e# q4 M4 `7 n! K3 Q
                         continue;  ; l1 G4 m2 `( p
                     }  + b# h6 F: I7 S" O0 }7 q: m) s, N
                     break;  ) [, \4 s0 T$ M& e$ i  I
                  default:  
$ l& @/ b+ F9 C. R) ^! I7 v; j                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  5 l& Z  @" t/ B# z' z/ Q. X
              }  , |6 Y" D( B" B7 l( q
           }  
& o5 f( ?/ J4 x& T! s           $field = implode(',', $fields);  
2 M$ ^: R4 i1 B. b: D% I5 v% _% }       } else {  
- H) o, S! ]" A, G1 [           return false;  
7 r! T6 I* C- a' o       }  
. N: `2 q( x! |* v1 U       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
4 k+ Z0 ?1 ^. b& H0 v; K       print_r($sql);  
5 e  u: Z9 X0 w) |6 C* J       return $this->execute($sql);  9 S9 E& Q8 Y& [( [- D
    }
% s7 s3 g0 ?" q3 T9 G3 x1 K; k从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ d9 }6 S! s5 x* I0 k& V. O( b, A+ ?
攻击测试:- [2 {7 N! u$ N% v$ y5 u
测试地址http://localhost
( w8 T% f+ z; b3 P; G5 M2 Q  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句. o7 v- U: c1 Z" H. U

+ {# k5 j) o' K6 R2 U" F 9 E/ P7 C& l: J" l# f* ~

+ H# t, Y* a6 N2 O' j) R7 ]/ u# E/ E  ~, V* I0 Q# l
; P2 N, O# S" F0 M

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表