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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告' L* [! p% I2 Z! `& M  z5 l& _
漏洞作者:skysheep
8 ?$ ~( G4 c( x$ p. r分析作者:Seay# z4 l/ S" B3 Y) ]( p4 u
博客:http://www.cnseay.com/
0 d& I8 h7 m5 i6 J9 D2 t# P3 G漏洞分析:2 v; t0 @! h) S; R" R
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
, I2 q! {& \  z) K4 y
* A/ U  ~& ~# I/ D+ k* u
; N+ l  q9 V# E. x, E( Y# r9 A# _. l
$ v  X( W* {% Z- Qpublic function account_manage_info() {  % X/ |/ j3 n; W' G. l
       if(isset($_POST['dosubmit'])) {  + U2 O# N- m  |& t+ F1 |
           //更新用户昵称  7 I4 R* v" v% {
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  9 r- Y3 D8 f/ h  `1 ?
           if($nickname) {  & f5 ^7 H8 Q- i/ `7 O
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ; C5 _$ r8 ~. i$ c# ^' \
              if(!isset($cookietime)) {  - V" [$ s  h7 A+ y! M4 l/ K
                  $get_cookietime = param::get_cookie('cookietime');  
# Z6 n* e, e6 a. }7 ~) j              }  
0 d. Q& h' P" R1 W  @. @- ]              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
; k" H. t& q. t# B3 j% H; p0 |              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  5 z' Q; F2 h0 n: f1 q) F: N( T
              param::set_cookie('_nickname', $nickname, $cookietime);  
; q: E: w. ~: Q# |           }  
% \8 H4 V, e* o' z           require_once CACHE_MODEL_PATH.'member_input.class.php';  + N# r3 H+ Z2 F  O5 \* h6 C/ L
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
9 s8 W& \7 @6 s( Q  c" k5 ~           $member_input = new member_input($this->memberinfo['modelid']);  
. I: d. R) V! {. H# e           $modelinfo = $member_input->get($_POST['info']);  
' x* n3 l/ b4 g' K% D           $this->db->set_model($this->memberinfo['modelid']);  . Y0 y5 s; h- L5 p
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
5 _- W. P( ^; k+ `8 n4 \           if(!empty($membermodelinfo)) {  4 o/ w4 Y+ l, y( j( w/ t1 }7 m
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
' n! a% e! B2 i  y4 ^* K2 ^! R           } else {  ( q) [3 }$ X7 ~2 o! t  j, T
              $modelinfo['userid'] = $this->memberinfo['userid'];  # u% o1 `8 T1 |
              $this->db->insert($modelinfo);  5 ]+ U% i$ X8 A- d- |
           } / P4 V" X  c7 |! I6 k
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
" s6 ]8 E- S: U0 c; e0 K6 u2 B在\caches\caches_model\caches_data\ member_input.class.php 文件中:% R) Y' {' B: o. |: U6 K! h# s6 W
- A  M( ^) @' v( G$ @8 P. `
. f$ J  Z* b7 m% `/ k( M

9 F% n, A3 p) @8 H# T: D5 j) `function get($data) {  4 [5 N3 R' H! t6 H4 H" M; s
       $this->data = $data = trim_script($data);  + k) F8 ^4 p' L. t
       $model_cache = getcache('member_model', 'commons');  9 Y4 e& v# D  w" K) k2 Y1 D+ b
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  6 p; [. d  U  [5 C# T
       $info = array();  9 f2 K' v# M7 S8 s8 v7 H9 x+ J
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
% Z/ _8 C, C$ N/ E% ]/ m/ G       if(is_array($data)) {  
' y, w0 _- F: f1 w           foreach($data as $field=>$value) {  - h9 V: h; E3 ~% H: T2 h' P/ h
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
4 z* I* d$ i) m7 [: \              $name = $this->fields[$field]['name'];    h+ }; A. ]5 e# g0 G
              $minlength = $this->fields[$field]['minlength'];  
: S  ?9 Y& c6 o              $maxlength = $this->fields[$field]['maxlength'];  * q$ y, I6 ~1 u9 f5 g' o8 Y
              $pattern = $this->fields[$field]['pattern'];  0 r: ?2 I. `6 u6 @; W$ c
              $errortips = $this->fields[$field]['errortips'];  , B2 n2 `% m6 v& U; }7 s2 V  q  X
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; C" K7 D" x' Z& X( n0 e8 q9 j              $length = empty($value) ? 0 : strlen($value);  : l" {. a8 j) [6 u) u( y7 E1 r( V
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ( i# Q; b0 e9 z! X/ F' B% r
              if($maxlength && $length > $maxlength && !$isimport) {  / g, x5 s4 Y  E
                  showmessage("$name 不得超过 $maxlength 个字符!");  1 \% G  ]# ~  k6 k
              } else {  6 [8 ^8 g" C' C8 c  H
                  str_cut($value, $maxlength);  , s% ?! u' s1 Y0 R, Q+ q
              }  3 B6 u8 I  c. S' t( v8 g6 D
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
# |, D' s4 Z! I- [2 q4 m* K                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
* o- _$ @8 k: T5 ?9 G              $func = $this->fields[$field]['formtype'];  # B3 G' U0 U4 i3 n
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
' I5 x. V/ U- i2 i; o              $info[$field] = $value;  
5 S" [' k! k; {0 S- S! ~( ?+ G           }  7 \7 [, w% p' ~+ }
       }  
/ l/ y" N3 K6 ^. W% S( r       return $info;  " c3 S& \& L# ^5 \( ?& C
    }
9 {# J  Y* @4 ~' gtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,; q9 p4 Y5 k3 o/ O' a! P$ j

! _0 D( Z8 I% E! ]再到phpcms\modules\member\index.php 文件account_manage_info函数
8 O+ p5 l! T; K; ]过了get()函数之后。9 ]. k( E. v( P8 T! a" k3 \

7 ~' C$ @) Z$ z' V, H
$ U4 A( E$ y8 U2 g% K" l$modelinfo = $member_input->get($_POST['info']);  5 z9 |  A+ {, p# q! n
           $this->db->set_model($this->memberinfo['modelid']);  
# p: x4 Z1 e+ e: B1 x* ~3 t           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 {3 T/ o+ N+ z2 R) s/ z
           if(!empty($membermodelinfo)) {  * K" j2 w+ {" z  ?2 s3 D/ a
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  5 K6 J" F9 a* W' I
           } else { / m! w5 T* x* F7 _" U  N
直接带入数据库,update函数我们跟进看看2 U/ [, S% m7 G& B! U3 d% x' f4 q+ p
- s( O8 Y5 c( @: U; @  T" `
# Y# ~, ^, [& _7 t# r
public function update($data, $table, $where = '') {  
: M0 Q  u& l8 a6 c       if($table == '' or $where == '') {  . B, N6 b, K) w8 y+ t- {
           return false;  6 v  N0 J+ z) Z* T4 }
       }  
+ v. t% v+ }4 [0 Z       $where = ' WHERE '.$where;  
0 q* U9 r6 h( s. c& a" I4 I+ f6 i3 }       $field = '';  
  N  g) n/ e- r* N       if(is_string($data) && $data != '') {  " J: D; _$ g, p6 x7 G% A# S# M1 a
           $field = $data;  
, b) k' }  X+ v' u, M2 m       } elseif (is_array($data) && count($data) > 0) {  
+ `0 W) C6 \* ~( A$ l           $fields = array();  1 M" b$ t! _5 l. J2 S, c$ \  R
           foreach($data as $k=>$v) {  
$ {9 }; n$ K# `5 F' ~  W- x              switch (substr($v, 0, 2)) {  ( d2 P- P6 F! Q) p  `8 n
                  case '+=':  
8 `9 _4 [5 V7 q+ h                     $v = substr($v,2);  
! C( v  `; U) v9 a+ f1 Q                     if (is_numeric($v)) {  
( Q0 |6 L& W: ^+ L! ?7 w                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  6 w( o& s$ B  a
                     } else {  7 [5 R* z4 {; A7 }( j  X+ q& F
                         continue;  # j  C2 _( z5 [" ^, c' Y
                     }  
; f" S5 h  T2 X6 }# N                     break;  
0 _1 ]' f, e' N, V                  case '-=':  
: q; |# n& l$ ^' ~0 T                     $v = substr($v,2);  6 ]3 _& |7 G4 {' l. l" h& p6 e8 \
                     if (is_numeric($v)) {  6 i) r/ V9 v4 q2 g4 B5 T
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
6 Q4 v+ g& n! q4 N1 ~" C. t2 Z                     } else {  
  D' f( g6 W' H; ?) E# d9 }3 m. Q                         continue;  ! j" E6 J' ~: u6 g) |$ x( T+ J
                     }    N* Q. g9 v0 g; F& Y" ?
                     break;  
! q1 D" Z/ F' n- B                  default:  : b8 a. r3 M( S/ G/ Q6 f
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  2 Q8 i( S4 c. @2 {" H
              }  
9 D1 r2 ~5 E" h" L# `  n$ h4 }           }  
) {- j2 n1 L+ F  |8 N3 F/ j7 O( ?           $field = implode(',', $fields);  / G& m7 h7 T" T
       } else {  0 j4 ]1 W. ?$ b( `3 v
           return false;  ; [% w% o& C! p+ A; F, z
       }  
4 I) p  B7 f0 M$ U, P       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  $ W& j7 U* W2 a
       print_r($sql);  9 }9 u6 L# r( o2 t4 j+ E5 u
       return $this->execute($sql);  
6 g7 Z" Z/ X  H4 u2 M: n/ |    }
# I2 V* \; H3 W; M, u从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ S/ m0 K9 t- a+ p( Z
# Y0 T8 ?$ p4 n6 ~  j; q4 |攻击测试:
0 a. |5 S, ?* m: k测试地址http://localhost
/ @$ L# s: S+ P$ d8 w- ^/ e  n  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
/ W" A. @% ~" A) @0 v! O2 h( o! q  I$ x3 k9 [

' z) q3 L5 l; y+ T9 I) K( ^' D. _
5 d8 F: t7 {5 J3 M' V/ o
# q0 T6 U: S" B' o0 a$ @- ?4 H: J- x1 |1 f- G5 t3 A

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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