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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
4 X9 S- u) M% ^% c+ `漏洞作者:skysheep- r$ z- e0 J* H! X- I
分析作者:Seay/ y# A- Y) y! {( {) w& a8 T
博客:http://www.cnseay.com/0 b- t* F+ }8 H* c+ O
漏洞分析:
" v' h0 P# `' L0 X1 B' \  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
4 q% t' a$ O" ]- R0 H* \3 L- [$ ]  B$ L- ~( _! @+ Y

* D+ u7 ?( s& X4 V
  q+ f6 _/ _! ?2 P3 w1 c& _4 P& Vpublic function account_manage_info() {  
) G- W# Z( f2 ]; e4 ]7 p       if(isset($_POST['dosubmit'])) {  
9 k  r5 O# L/ Q. T. v( J' s+ d           //更新用户昵称  
) M$ w6 [7 N- H% K) |" O! B           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  5 o% H; H% }) ~; @2 v6 C
           if($nickname) {  
9 d, ]$ |' H  L% d- o              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  * u% W! _7 V# U, o4 C$ W
              if(!isset($cookietime)) {  ; v3 |9 c' R* J* c
                  $get_cookietime = param::get_cookie('cookietime');  . P! u0 _- A7 [" P1 W
              }  ; |/ m( q/ c, |/ ?. x3 ]
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  7 R! ]& Q: ~# `# ?5 k
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
4 d( \8 g# f7 T# r% d) x              param::set_cookie('_nickname', $nickname, $cookietime);  ( K3 j8 K; }5 D
           }  
. O% g7 x- R5 y# x! s8 x8 D! w, ^4 A           require_once CACHE_MODEL_PATH.'member_input.class.php';  - k3 o6 a  i+ P, A
           require_once CACHE_MODEL_PATH.'member_update.class.php';  $ Q+ u! w5 P- L! F1 i
           $member_input = new member_input($this->memberinfo['modelid']);  , \0 d2 Y* Q, Z
           $modelinfo = $member_input->get($_POST['info']);  - t) g/ I" K) M; i7 W
           $this->db->set_model($this->memberinfo['modelid']);  4 |4 ]7 _# X  u& Z4 j
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
. a* t& U9 j0 w/ T: t6 ~, d           if(!empty($membermodelinfo)) {  
& c: k. ^, x$ m: t! X( n              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  3 f) a  C8 d! N2 _! @( I
           } else {  # g5 v; g3 b' A4 P% X
              $modelinfo['userid'] = $this->memberinfo['userid'];  + p! _6 ?: M& W2 F' z& M' D
              $this->db->insert($modelinfo);  
- N& ]1 {' Q! c           } 4 E# S: ~5 r( m: X" O& k2 |5 ^
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
* S+ V1 ]& z9 |1 |) ~" N6 j在\caches\caches_model\caches_data\ member_input.class.php 文件中:8 K9 N! g8 c9 G7 ~  K+ z( s

% J. y9 d2 z1 M$ x4 ~0 ?' d9 P
  O7 T) e1 A* y& N: e: N! I- l
0 l8 f2 z3 R! G  E+ W+ g- @* Lfunction get($data) {  
6 T) U+ N7 L* e; K       $this->data = $data = trim_script($data);  2 W, H7 u7 e$ D) I& ^4 }* M" S/ ~7 j" ?
       $model_cache = getcache('member_model', 'commons');  
* y+ O$ o# J- B       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
" k% i" g% h+ _3 J  z. M       $info = array();  % R. i- q- R$ C% F1 Q
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  2 E5 D% H/ C7 g6 S$ {8 d9 d  `
       if(is_array($data)) {  
* _! o3 K7 m7 S' }- {$ e           foreach($data as $field=>$value) {  1 X# I6 u! a7 g2 f$ u7 p! p- }
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
. \2 P$ L+ T, p  d3 `              $name = $this->fields[$field]['name'];  
1 l" `% Z5 m, M3 r0 E              $minlength = $this->fields[$field]['minlength'];  ' {8 R% W3 `# N9 C* n
              $maxlength = $this->fields[$field]['maxlength'];  & v7 U; [0 f5 U2 |! ]
              $pattern = $this->fields[$field]['pattern'];  9 u8 s- V* J# _9 `
              $errortips = $this->fields[$field]['errortips'];    \1 [) W% g  ]* p% O# c0 O  N5 D3 E1 g
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
( v& g) y7 U6 C              $length = empty($value) ? 0 : strlen($value);  
6 D$ R& o: `1 h3 h              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
+ I* Z6 u6 g) t2 r0 t" V              if($maxlength && $length > $maxlength && !$isimport) {  7 i- h; a4 z0 A/ T. f
                  showmessage("$name 不得超过 $maxlength 个字符!");  9 h) D! Q- H7 l9 j3 U
              } else {  
6 n$ {: o8 V. H9 i9 \                  str_cut($value, $maxlength);  
  I* E' [: w7 m              }  % N0 z5 E+ u! Z0 F4 a* M$ X
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  6 T6 {$ G# q. Z1 g7 |
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ( M* z" h' C4 @% [8 Y/ R6 S5 J( w% h
              $func = $this->fields[$field]['formtype'];  
; Z+ _. D: B+ {# v7 [              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
7 x* b# E$ a, W8 B5 d              $info[$field] = $value;  
7 e0 }5 h) Y* Z4 j6 i           }  
( A# [& X1 _# p7 c6 W; T2 U       }  ( N% k9 L. U& l' u$ \2 R
       return $info;  
' R# Z4 H0 `, o# l/ }! ^: U9 b    } , ^5 ]8 q9 m4 |: T* n
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,! i8 a0 y# m# W6 |
' x' I( U% Z- ?- k  C" F
再到phpcms\modules\member\index.php 文件account_manage_info函数
; }0 k8 t- n2 ?: K' k$ V) `过了get()函数之后。. C7 a& U) @  M) {# ^

6 ?$ o4 X0 I5 n' z7 Q
3 A1 k/ M7 k  t( C1 D# l$modelinfo = $member_input->get($_POST['info']);  
, c4 N$ J; [$ o9 d6 }           $this->db->set_model($this->memberinfo['modelid']);  ; d/ ]+ T; V" i3 p  ~
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ! ~) j/ c9 q) M/ y% `
           if(!empty($membermodelinfo)) {  
/ d: o; m5 g, w, ]3 E" q' r8 K              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  + G2 l8 L* D4 e1 L3 D3 }" w
           } else { - Q# i: G6 g" ?2 z  P* S1 |0 ?
直接带入数据库,update函数我们跟进看看
% `" K+ `) ?. L+ v* E3 O% O" J4 d  V. N/ ^. d! ]0 V" B% N

7 r6 G" S& {9 S/ S; p/ W1 n2 ~public function update($data, $table, $where = '') {  ( B! t- k& c1 M9 p
       if($table == '' or $where == '') {  $ N  _  R0 C/ a! y9 W; O' A
           return false;  ' \7 G( P' s# }$ R1 J2 m
       }  
. [# k2 {2 A& @- d$ I       $where = ' WHERE '.$where;  
& Q9 y2 J. K3 k3 F6 _$ i) k  A       $field = '';  8 Q" K# D* M2 F! w7 z) E
       if(is_string($data) && $data != '') {  . y! I+ D% u" t
           $field = $data;  
& P$ K6 D9 l9 i- a0 M0 O- q- C       } elseif (is_array($data) && count($data) > 0) {  1 M  L1 S8 V7 i( J$ k
           $fields = array();  
# Z/ ?" [: S1 k; M1 |, U           foreach($data as $k=>$v) {  
7 S. D: }" @( a" E3 [7 i              switch (substr($v, 0, 2)) {  
# L6 D: X+ @7 l                  case '+=':  , p7 |2 i  U4 r4 }
                     $v = substr($v,2);  
; @% n# \& P0 j: ]                     if (is_numeric($v)) {  8 h2 N' X6 s5 i" [3 f$ x
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  " X8 Y, q/ g4 ^) p) f
                     } else {  0 n- O* p, ^/ v" s4 [5 M
                         continue;  & @+ p0 z% [, b* U3 ]6 X1 s
                     }  4 M( f2 n  E. K
                     break;  
7 z, O( `+ O' c: v                  case '-=':  . ^; ?- Q. }7 P
                     $v = substr($v,2);  . s$ A7 i/ ], J, {
                     if (is_numeric($v)) {  ! v9 v( ?  A$ ]: X$ V( k
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  . H1 W' O/ g7 S1 a
                     } else {  
8 o# G" f# ^: ^0 }                         continue;  
& U1 X2 W" V0 m                     }  
% L3 @  l/ N0 W. I                     break;  : m7 t  m! t+ g* S8 }5 T
                  default:  " \* T% R/ z/ J4 ]
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  6 h/ T0 ~5 f  D6 T) H; P6 S
              }  " @; O# A( G( e8 _9 E9 l. ^
           }  
0 A9 ~( m3 i: y2 Q+ Y7 ]7 h5 |           $field = implode(',', $fields);  3 g8 @0 `% ~7 D) L2 k. T% |7 d
       } else {  
  ?" r8 c1 J+ L: P! b; [           return false;  
4 b6 U+ I7 d, \, T* G       }  
/ l7 {+ f1 e9 V" {2 K       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
, \) d/ X$ A0 a2 T8 z* Y6 t7 D       print_r($sql);  
! R- O4 p% ~' W( X6 Z       return $this->execute($sql);  1 [' V9 ^7 I2 k
    } / `; A- l" I' R2 p
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
) L6 _, W3 E2 i; C. }# ?7 H9 i8 u; L
/ M# l" L: L. f* F1 G# |攻击测试:& U  G4 B, O( W$ c3 v
测试地址http://localhost
2 q$ H0 s0 k3 R5 u( K! b  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
# t% [! ?- l7 t. g8 `- ?0 P  N1 J+ a+ L9 P6 Q
' I0 d9 p. r- v* n  y. b
8 U" b3 N  q; u. u' [

" E7 f5 E- v! c! M2 L! r0 S4 ^, e2 a
* {& ~# \3 ^2 y/ t- E' \! i  A( H

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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