找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 2169|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
8 O& k" f* C$ B( ?9 r# ]' t漏洞作者:skysheep* v! k! M) [+ r) `
分析作者:Seay3 t* W0 e' R' C+ {
博客:http://www.cnseay.com/. e3 c* L* ]0 \2 E$ ^5 k8 ?
漏洞分析:, K# A5 _. n/ ^  w9 l$ m
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。- ^5 Q( p$ r3 I% L. n

1 v( A( {) E% L. h1 ]/ v7 g& n' w  W% X% y: j  I
  |: u: |4 I% m' R
public function account_manage_info() {  
; o( N* j1 Y: J2 O       if(isset($_POST['dosubmit'])) {  . T/ J8 [" F1 U4 J- C. B
           //更新用户昵称    U( d1 p) V7 B+ P
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  2 x( @! o; [) J; m; @2 D8 s$ q
           if($nickname) {  0 Q- Z$ j! s7 C: \! q
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
7 O6 b/ R8 D# l/ B8 M7 P' g& I: k              if(!isset($cookietime)) {  * H* }* m( V- \" n. ~7 O2 _& q! C
                  $get_cookietime = param::get_cookie('cookietime');  % `) z: h' m$ g0 [7 r7 r. G
              }  
" O# s, E( K5 s# |& t/ }& C              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
, Y  X; ?; u" T& }# T  p: Z0 t              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  7 M9 F3 V5 {/ m( f5 ?& i
              param::set_cookie('_nickname', $nickname, $cookietime);  5 n% I' ]1 y+ }0 x  ^8 F  C6 K
           }  
; y) o6 r' M2 y2 Y6 Q2 s: P           require_once CACHE_MODEL_PATH.'member_input.class.php';  6 i8 h; Q& ]' A& L3 B3 w/ H7 Y
           require_once CACHE_MODEL_PATH.'member_update.class.php';  ! Y, K# z0 u" k. ?; ~4 k& O
           $member_input = new member_input($this->memberinfo['modelid']);  
4 E3 E. y* E( T0 a           $modelinfo = $member_input->get($_POST['info']);  / q. {& X* d9 K1 a$ b
           $this->db->set_model($this->memberinfo['modelid']);  
$ n+ e2 g& J1 ]) x" G# `* {           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ; b( S/ D  b9 s& J" a
           if(!empty($membermodelinfo)) {  0 u' n1 g# B0 s  Z1 C% w
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  3 u' z7 Q) I8 s' D- d* T
           } else {  
& g9 ?; ?/ N: n- F7 |) n6 e              $modelinfo['userid'] = $this->memberinfo['userid'];  * H& F8 Y( g- ]6 D6 C: L# h
              $this->db->insert($modelinfo);  + O9 Q! W/ T: D- ?
           } 7 l9 y/ N7 l8 y4 z" Z/ Y8 m# A4 T
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
1 X7 v9 b) U* l' l: [在\caches\caches_model\caches_data\ member_input.class.php 文件中:! w3 \; N7 y, k' q2 Q! \7 [
6 s7 n, t; H: J* P- x
3 B. k% `4 o1 c/ F4 k: N7 R

- U9 N+ t0 s8 }, Y( R( Q2 ffunction get($data) {  
3 M5 U, y7 k: t5 i: O! o       $this->data = $data = trim_script($data);  
$ j* x. o  I% O$ d       $model_cache = getcache('member_model', 'commons');  
- G. \3 s! X0 {# \5 d' ^, ?# w       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  9 O( ^+ x" K9 A% B1 ]
       $info = array();  
- ~+ f7 Y# H' v" w       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
6 w7 o9 F. M; b' i" W       if(is_array($data)) {    c% V! @8 {( l- s: c" ~
           foreach($data as $field=>$value) {  : w. m1 R5 y1 p  q3 d! h
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
5 q# r8 Q: A! P% J/ n' N              $name = $this->fields[$field]['name'];  . q9 u- W0 C( }$ L8 t# j: M0 f
              $minlength = $this->fields[$field]['minlength'];  5 o/ J6 m/ l9 y; J& a2 X1 Y- [! O& w
              $maxlength = $this->fields[$field]['maxlength'];  - Y5 V. K, r" L/ O- u9 {
              $pattern = $this->fields[$field]['pattern'];  
! _! A8 P7 Y/ i# B) L/ l: e- g              $errortips = $this->fields[$field]['errortips'];  , g% p$ M2 F0 ~( h( a
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
) X& O. q: n% V/ M              $length = empty($value) ? 0 : strlen($value);  , y( U/ v6 p/ |0 {( Y8 O: V) u# ]
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");    f7 y% b% h/ D) }5 d$ _4 n$ M
              if($maxlength && $length > $maxlength && !$isimport) {  9 [. q( f5 `/ p7 }
                  showmessage("$name 不得超过 $maxlength 个字符!");  1 T, Z% N0 w' g4 n
              } else {  - f" R) Q  e( I$ R8 \/ c
                  str_cut($value, $maxlength);  . ~) k& j" i7 C% u$ {' P9 @& k; Z, s( z
              }  . y. G( T! ?+ @. I/ C2 k) ?% q
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! X- j7 U( d% Q; c; N) d; Q
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
* J6 D4 M: Q. d3 n& V+ l0 z              $func = $this->fields[$field]['formtype'];  & D' v, [) ^" L  K1 R
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  4 A' g; j( @4 t7 p) }
              $info[$field] = $value;  9 R( V& G6 B0 o! J
           }  
1 K6 f$ Y, }  `       }  
0 Y6 u( e0 W' @  d6 I' c, o       return $info;  
2 m" ^6 m# s$ p" f7 r    } . p& X' V. i; t$ `, y
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,7 q1 J/ P' M3 @9 T
, g' u& Z5 b7 `  G" S
再到phpcms\modules\member\index.php 文件account_manage_info函数+ w6 A' }$ {* U' L7 k; x. K' f
过了get()函数之后。
' C& p9 i2 L) A4 |6 }' {7 ]( h  C& L& M; [% j4 q* e8 @+ h
8 d- D& Z$ |, }
$modelinfo = $member_input->get($_POST['info']);  - d% b4 M! C' e5 [1 i
           $this->db->set_model($this->memberinfo['modelid']);  
$ V# b( P9 h& j' A, W$ }7 i6 l           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ' k& C$ B) z* L# T5 `
           if(!empty($membermodelinfo)) {  
+ m$ G; b3 Q' d0 U              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  7 I# p; _" R+ u: R" n9 E5 _
           } else {
4 j3 A, n4 w7 q直接带入数据库,update函数我们跟进看看# }/ W: O" l+ h# r% h, p, A6 J& Z

* p" w7 j! ]+ w' T( d9 ~ + U1 d2 X1 a& j- J
public function update($data, $table, $where = '') {  / Q+ a3 D6 T- I
       if($table == '' or $where == '') {  
) Y( B( n! V3 M$ k8 i: g& a7 ~           return false;  
$ {, W" Y9 T0 ~; k; I8 A+ Z       }  
2 |9 S0 o: ~+ ^" t, g. k; |       $where = ' WHERE '.$where;  * _$ x2 s/ j6 c- _
       $field = '';  
$ D8 I7 b" ?, [, v       if(is_string($data) && $data != '') {  - a$ Q) S/ R. |% M8 ^0 d0 P% G+ o( f
           $field = $data;  
# S- ^) z/ J. p( @! I       } elseif (is_array($data) && count($data) > 0) {  
2 N! W+ y; G2 u* D           $fields = array();  
1 z! _& K0 F" Y% J           foreach($data as $k=>$v) {  0 v% g6 K# M2 D% f, y
              switch (substr($v, 0, 2)) {    F: R+ v' R" |6 v, M7 \
                  case '+=':  
* F2 N0 D; Y, I0 c9 Z* X                     $v = substr($v,2);  
- w" G" P0 S& ?8 N+ h1 J; K( W                     if (is_numeric($v)) {  . n4 h' Y2 N& E0 C, D5 S- U0 c( N' W
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ! c$ v" E4 u2 H9 @) c
                     } else {  : ^3 }* j# e  A
                         continue;  
& J! h8 ~2 a! F- O                     }  / u# w& B# P4 a. B! z. U
                     break;  
3 w/ \) E7 O4 G, S+ A' X" u7 B( @                  case '-=':  # V+ Z( p9 L) t2 E
                     $v = substr($v,2);  
( s! D/ E! ~2 E2 H6 e% ]                     if (is_numeric($v)) {  
- G, i+ L/ Y, e0 A/ O) O& E                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
. B0 ?1 L% B+ Y) a/ \1 g                     } else {  
  |* ?+ A, ~* B  B. N! I# e                         continue;  
& j/ X* _1 J2 B# J                     }  3 V* k: V" Z* Z+ C. `
                     break;  : d7 w! V8 Y7 J# L! K" G. r
                  default:  
+ _  |. R/ d7 U+ {) O                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
4 u/ F0 ^5 s! ?4 y7 D9 X              }  
! R4 Y9 D1 C- H5 h7 `           }  
7 T1 V0 R( S( n/ k1 v" O2 i           $field = implode(',', $fields);  
1 x0 g! L1 J/ ^: j       } else {  / g4 P# D+ _- H% y1 _4 l
           return false;  
5 z3 |, f  m" d  [- {/ L       }  
; g% |3 W6 ^" D8 F6 V       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  " B4 H. G' c# J( F  j8 a* ]; W. g* Q
       print_r($sql);  , P" Y0 b6 _5 {7 A5 \
       return $this->execute($sql);  ; @* S/ D/ T0 F  ?# w2 b5 F
    }
& K% Z6 a5 P. ~  `4 b$ [" |从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。, |7 f  P; q5 H' @5 |1 a- y

$ Z7 C+ p) k3 ?  m% m0 I攻击测试:+ `9 S) d# R* C
测试地址http://localhost( X, z7 b( x  y7 W% w
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
* k! o. P! R7 |5 `6 Z8 \
+ S6 R/ H+ T  C6 L% ?0 ], W5 c 9 |: z* V- K! k

& E8 A. n. ?* P3 T. h. h. I3 J; ]7 n- x" j" `7 Y6 v, E

1 e) ^. q/ f% f. {$ L) Z) ^

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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