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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
& V3 n* O* m* X漏洞作者:skysheep
$ y6 g5 M! p2 H4 d" L6 ~+ U分析作者:Seay
1 B; g- Z: Z. p) F" p2 w! v4 J. w博客:http://www.cnseay.com/
7 f/ I, e) A0 w% L: Z1 o6 N6 q漏洞分析:
6 p& ^4 D" o6 a8 b/ R( q3 o  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
7 r" B: j/ @6 h/ d! E. {/ r. W2 \2 f9 Y0 ^) b: N3 u
8 ]! Z" O; u% v! P0 e
: D1 u; J" {+ Z. N
public function account_manage_info() {  4 @" ^; A4 S. E% t: ~0 ^
       if(isset($_POST['dosubmit'])) {  0 w+ I6 T! C8 t8 j
           //更新用户昵称  
" J! G- s. \/ D  }- @           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
/ P7 O# L; d. Y% p           if($nickname) {  
' H4 y" j. ~# b              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
, i* L, G/ n1 h5 t7 I              if(!isset($cookietime)) {  ! p1 f' `, E* V$ `. F7 A3 d& c
                  $get_cookietime = param::get_cookie('cookietime');  
' ?( w, G8 C0 R& @; P) Q9 v; X              }    z0 k9 O! a# O! P( B( m
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
% V. g6 s$ d9 \6 r0 C0 j0 @              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  5 v' \- e6 O, n
              param::set_cookie('_nickname', $nickname, $cookietime);  
0 [+ Q, k) j3 n5 t           }  
9 D  @( c& r2 i) f1 y% e# l           require_once CACHE_MODEL_PATH.'member_input.class.php';  2 A; K$ i! i+ _3 @; k5 O, C" c
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
! R, Z. t6 A, F9 W3 T( K3 s           $member_input = new member_input($this->memberinfo['modelid']);  ) j( a( W* x& [  l) i7 b+ ^
           $modelinfo = $member_input->get($_POST['info']);  
9 u- `$ U( x+ E8 O% L; ~           $this->db->set_model($this->memberinfo['modelid']);  + P: S7 I+ t/ S( Y; j
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
7 b$ P5 F1 z. E' s/ J           if(!empty($membermodelinfo)) {  # s! \3 l  Y3 i' f( ^* G
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  8 M- _$ e3 n7 g! N+ m1 m) L
           } else {  
. z' v: e. F- ?2 u% u; ~+ O$ U              $modelinfo['userid'] = $this->memberinfo['userid'];  
( T1 O, B5 X) o. w5 V( S/ w              $this->db->insert($modelinfo);  
  @& o- ^; ^# v# E: x           }
4 ]: w" x. g8 t代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,/ _: X# k5 W( E
在\caches\caches_model\caches_data\ member_input.class.php 文件中:5 x$ r# ]% k5 a7 y8 L4 a9 s
  A9 c  _2 d; U
: u; q$ @3 O) i, ?0 j
9 ?! q$ j8 k! ?2 N. @
function get($data) {  
5 U) M  ?' |$ a. q% L: Q! H       $this->data = $data = trim_script($data);  
0 s* D  ?/ r2 G. T4 y4 T       $model_cache = getcache('member_model', 'commons');  : ~2 X9 }5 f- }6 k  a$ q: {
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  : [  U- d" r- N6 i: _
       $info = array();  ! v) r- [2 k0 z
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  7 Z2 y: r2 W' _  }0 s. A" [
       if(is_array($data)) {  
# J1 P6 }0 Q: q. v           foreach($data as $field=>$value) {  9 M: X/ S. S6 E# l$ g' [0 v% `  z
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  . f8 v( q6 F# t6 t. l7 m
              $name = $this->fields[$field]['name'];  % a* d8 f6 r+ s* j; \; n+ j
              $minlength = $this->fields[$field]['minlength'];  
. o$ h) G# [; m              $maxlength = $this->fields[$field]['maxlength'];  
5 z: d  i. v) ?6 `9 ~. M; c              $pattern = $this->fields[$field]['pattern'];  
8 I5 E" S1 d7 N6 J              $errortips = $this->fields[$field]['errortips'];  ; I4 x9 p; h7 f6 X2 M* _
              if(empty($errortips)) $errortips = "$name 不符合要求!";  * H* ^# A7 X. f( q$ Z$ Y
              $length = empty($value) ? 0 : strlen($value);  
& R( Q' W/ l$ y* j. P              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
  D! ^5 N7 n6 x% Z) K' t              if($maxlength && $length > $maxlength && !$isimport) {  
) D6 G& U7 ]: A. C$ |6 S7 d- u                  showmessage("$name 不得超过 $maxlength 个字符!");  ! A/ M5 Z5 T, J0 P) W+ L
              } else {  
6 s, E6 c9 O2 q( |9 g0 S" k                  str_cut($value, $maxlength);  
% Q+ S! R5 k; O2 B              }  + p! Y, \: n7 Z! `6 }( \$ ?
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
; k+ d* N8 n- k/ \1 l                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  " L3 L1 F% R  w* x
              $func = $this->fields[$field]['formtype'];  
' t, p2 v6 q+ I              if(method_exists($this, $func)) $value = $this->$func($field, $value);  6 ^  A" E; v! \. h
              $info[$field] = $value;  4 A1 _- U3 V; y8 t
           }  ) G/ u& M5 Q! ]: Z, h' Q# K5 s& H
       }  ' ~9 B* `% ]4 q8 k# |
       return $info;  ( \9 g! X) o4 A- H: R5 s* c& ]
    }
: _; X5 |. D( W, Z, \; t& z  d- m! O! \trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
: Z: b. R5 |+ {) r  l' m; |: b
) @/ q$ f  g4 k再到phpcms\modules\member\index.php 文件account_manage_info函数
+ S9 ~- X! P4 T$ _3 ~! n  D4 u过了get()函数之后。3 a. {* P8 V# ~" m' B- @

- f6 h6 A( c- ?& J& x8 ]
4 U( R7 u$ M1 T+ p2 e1 p5 X  Y# r$modelinfo = $member_input->get($_POST['info']);  
/ V+ j/ x  f8 V. }7 E: I- I* e! s           $this->db->set_model($this->memberinfo['modelid']);  - N3 X% S# h0 A) E
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  2 b5 I% |- J' Y1 R0 w* S9 w, C
           if(!empty($membermodelinfo)) {  : D0 U) g7 C0 _
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
9 K- D  T1 c# c# Y; \. V           } else {
  V" ^, ~  \9 [( }1 `) Y" V# u9 d! W直接带入数据库,update函数我们跟进看看
8 U% h4 r7 ~" k+ _, q  d​
- T+ h' Q) b; l4 Y7 a$ l * g$ X: \/ n6 S2 D1 M
public function update($data, $table, $where = '') {  
* @4 N" I1 w+ ~1 k1 b8 O       if($table == '' or $where == '') {  9 O( I3 L1 q$ A& X  V& I
           return false;  1 ?) W+ S) T: X2 c" L
       }    x  N4 ~# h+ m+ d4 ?  {
       $where = ' WHERE '.$where;  4 l% t7 I' d5 ?
       $field = '';  
/ R4 T2 f2 @& ]       if(is_string($data) && $data != '') {  . O; E7 M3 k; B& l& E, w
           $field = $data;  4 c, O# Q& d' O
       } elseif (is_array($data) && count($data) > 0) {  
, `! i+ A9 J. C$ }+ ], J7 b: g( k           $fields = array();  
# Z2 j/ [  R7 f( i: i           foreach($data as $k=>$v) {  2 b0 z8 \1 j0 _" ~/ x/ Y; b  R0 g/ r
              switch (substr($v, 0, 2)) {  8 X* I! D' N0 R1 {
                  case '+=':  
! s' ?8 L& ~8 g! A& O                     $v = substr($v,2);  
+ E' r8 S( Q5 b; z7 Z7 }( e! c* F* @7 H                     if (is_numeric($v)) {  
/ [) l2 }' ]/ X+ {# @* ^6 ~6 k                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  . |# L5 ^4 X' M# ~2 t6 J/ R
                     } else {  
, x; g2 m8 q9 v                         continue;  " b, L/ F0 I6 A7 \' {
                     }  
+ ]3 ]2 V8 [7 Q, t" r& s                     break;  
1 v3 D6 S* }2 ~                  case '-=':  / ~$ @; m9 y# @" Y6 S' X, j
                     $v = substr($v,2);  
7 l2 e6 A6 g9 M, Q                     if (is_numeric($v)) {  * d6 U0 W: U+ x- m7 a
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ( m; `; j) E/ i8 I, z) Y
                     } else {  ( g* n) N" ]7 W( X
                         continue;  
- q; o! l9 M: Z" z                     }  4 d/ c$ R0 I& g( [& W
                     break;  . Z" B  I+ p6 [% t, O
                  default:  # k+ @+ D! y! Z- Y) X1 S% O
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ( h5 P! h0 E8 C! m: V8 R! i  K" {' [& A
              }  * u7 i2 R. x0 y- n
           }  
1 u/ X6 s$ g- v+ n9 _1 c           $field = implode(',', $fields);  
' w8 s4 F7 \  \4 P8 t       } else {  
. B  y% ?# D( B. N5 T4 ]           return false;  " J3 H% H8 W% N- l0 p
       }  + z. e* y' M& E7 B2 `* G
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
) Z# M5 {$ T8 J( L# u- \5 f5 J       print_r($sql);  
5 Y7 {- }8 U! B       return $this->execute($sql);  " M) `' m( _/ S' P2 _: @/ f
    }
3 q$ j: |( L! W! D5 a& V& O4 d& d从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
: G3 C1 p( ~$ z5 o# `- ~
* q8 j, V/ e3 y, d1 u3 ^9 t9 a) T攻击测试:, f, [" Z" O- k+ G: R
测试地址http://localhost4 G$ G: C5 {# f3 W
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
" x1 f5 e4 R8 x) J! }2 e
5 L( _3 o3 u; ?. @ & Y0 p/ o  _5 w
+ n; X( A9 y* a/ L& ]& Z7 G6 }
' p- a6 q( r7 i# P1 z" K& t) c

% V. o7 a0 v8 c8 ~5 y" z) d

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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