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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告/ u! A! H- S; |- L5 ~( R: t$ @+ E2 y7 M
漏洞作者:skysheep
$ O9 n! i: T  a6 A" `2 H' C1 `分析作者:Seay" s# l2 c5 I  K4 I
博客:http://www.cnseay.com/
' E- h% D  m3 x) ~1 Z7 `% ?/ W) q漏洞分析:# r/ U& M1 R6 K/ u+ U3 }+ c- {! M
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。3 d8 m* [" ]8 e, @6 K& L0 ~
1 T5 ^6 M. e% n# d: E3 X

$ M+ \2 D( ]9 V; p2 t* b8 _  b
; M3 K4 t8 R- i, H! {public function account_manage_info() {  
  i! w4 ~4 `* p7 E; H# u: D       if(isset($_POST['dosubmit'])) {  " R  x' `: R. |: x. y8 @" R  }, y3 j$ T
           //更新用户昵称  ) }. A7 j3 B7 e
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  9 }  n. D9 U6 n! X
           if($nickname) {  
6 f) G# D  t+ K, e% Y              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
. I$ y: k  m2 |& A3 E, ^2 Y              if(!isset($cookietime)) {    O  H. i) b0 Z" I1 U; g/ }+ M
                  $get_cookietime = param::get_cookie('cookietime');  
) E) K4 S- ?. Z! B  p" k; w              }  ( k2 ]4 M, w* h& l' Q$ j
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  & ^* {; `: C, ?( X0 q* j3 t6 B% z
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
! F8 f) Q& |6 S$ X) E              param::set_cookie('_nickname', $nickname, $cookietime);  
9 ~- x# R8 i0 L+ p* m: R           }  
+ v. I+ j# `2 Y1 y; b" C           require_once CACHE_MODEL_PATH.'member_input.class.php';  
* k, D9 e: @9 c/ o1 r, V1 L           require_once CACHE_MODEL_PATH.'member_update.class.php';  
! R; Q5 \! l2 c. m4 j           $member_input = new member_input($this->memberinfo['modelid']);  
. Q+ F! }5 ^+ n3 y: K9 L           $modelinfo = $member_input->get($_POST['info']);  ) o+ @8 ~/ d( `3 G2 X5 O
           $this->db->set_model($this->memberinfo['modelid']);  
9 F( }3 M# @9 S/ L/ @           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
9 T3 k0 |( E9 H! o. |- o           if(!empty($membermodelinfo)) {  5 y4 M& b2 R- p# P: N4 L7 y( C
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
  O2 e$ |7 x4 [+ C) w6 ]  s           } else {  - x$ i' g4 I3 L6 K5 c8 }2 Y4 [
              $modelinfo['userid'] = $this->memberinfo['userid'];  + b. }7 F& x& I" y9 y/ |
              $this->db->insert($modelinfo);  2 `4 y1 `4 z/ y
           }
# ?( |9 A$ G; u2 H+ O代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,( m+ |0 I( m0 |5 }7 r8 ?8 G* b
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
  X" _5 K  p/ s  D% ]" E
# |* u/ \: [9 _( n1 w& B. V& a" K
# i$ X: E- o- `$ a! F; r
8 I% B) Q2 \4 c, Y( @function get($data) {  
0 E& P' S! C* K4 u) R0 p0 S3 v       $this->data = $data = trim_script($data);  # ?: x) n: A; C/ Q9 R( d0 d9 o
       $model_cache = getcache('member_model', 'commons');  
4 t: h# N9 s2 z( Q% _       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  * ^$ {. ^6 x  j4 X' e
       $info = array();  " r( j# H  [: d, ~$ |& Z: V
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  # p# R% @; B* e5 t/ S
       if(is_array($data)) {  
1 d8 z" E+ s0 }7 |6 F1 D- G           foreach($data as $field=>$value) {  
2 V+ _+ V) n' r4 J: n              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  6 y( Y  ~: N: I$ ]: U2 L
              $name = $this->fields[$field]['name'];  
3 w! ~- Q4 J. B) L. D* L              $minlength = $this->fields[$field]['minlength'];  " {# `( A* H+ Q6 S
              $maxlength = $this->fields[$field]['maxlength'];  
9 p4 i5 P, j2 r! U; o              $pattern = $this->fields[$field]['pattern'];  
) a0 [1 _* ^  p1 a2 M1 Z              $errortips = $this->fields[$field]['errortips'];  
/ h4 }6 B+ D9 T' j6 B/ H$ j              if(empty($errortips)) $errortips = "$name 不符合要求!";  
( Z) e. S9 u7 \4 w3 p; f) S              $length = empty($value) ? 0 : strlen($value);  0 c  K5 A; t+ K0 T  A+ r$ ?
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  3 A+ d% N8 q* L6 w/ Y. C! n
              if($maxlength && $length > $maxlength && !$isimport) {  
% E3 A$ J' q. P8 u& ^  ^$ j                  showmessage("$name 不得超过 $maxlength 个字符!");  3 x* g5 O( b$ B$ M. \
              } else {  
/ K' p9 P: f8 \  P" r- G  B' s1 w                  str_cut($value, $maxlength);  ( L2 Z: ]- V6 v+ x8 n$ G6 E4 \
              }  
. h* M- }8 z; _7 c1 I: l! X              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ' ^0 t( ^+ X! r- o9 @& z! j* e. f
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
! W6 J5 w" E& B3 c              $func = $this->fields[$field]['formtype'];  9 `* I, z1 L- f8 ]
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
' z$ r; ?# z' S- m* |1 S              $info[$field] = $value;  - B; f6 u. y7 x5 e
           }  4 w1 B3 A$ j1 W! R% G5 U# W
       }  
; k/ X  h* A$ G- y1 G0 K- r       return $info;  
# H6 y9 F, p/ d: l: n* s    } & e" x- p5 U- ]) e4 H! N4 P
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,0 `4 U2 C& X. S' i

+ z! d% S2 r& I. u再到phpcms\modules\member\index.php 文件account_manage_info函数$ \2 ^- V- d. E6 y* S6 V# O
过了get()函数之后。, `! @) r- k' X8 q

4 T& X8 L% E( c& y, ~ - b1 M+ T7 H+ h1 n
$modelinfo = $member_input->get($_POST['info']);  , f5 c4 S4 J; \! b! }5 @
           $this->db->set_model($this->memberinfo['modelid']);  
* V' Y; g6 |1 _           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  7 @( E1 {) M: g9 ^% z3 _: e
           if(!empty($membermodelinfo)) {  
6 n% r- x5 ]* ~1 \6 n              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));    ^8 z1 Z- j3 A2 i5 p
           } else {
& B  ?. g" d# Z  D2 G: W5 Q直接带入数据库,update函数我们跟进看看
) Y" ]! u5 e0 r. N' x
2 h- @; y+ ^& u' s$ N  ^ 0 s5 q7 F2 f. Z2 `. C
public function update($data, $table, $where = '') {  ( {" |* p( G/ ?  w. c
       if($table == '' or $where == '') {  
. J; d4 l3 ?" W/ T  F7 s           return false;  " t9 W/ Y  k: A' d. E9 [
       }  - h% `  z5 b* ~, V; f
       $where = ' WHERE '.$where;  7 I" @. k  V) _- g4 f7 z+ j2 l  B6 s
       $field = '';  2 W0 r( i& x% l- j1 t$ W
       if(is_string($data) && $data != '') {  
4 P! {: Z% a( Z) R; q           $field = $data;  . G0 f4 @& F& q/ e/ b
       } elseif (is_array($data) && count($data) > 0) {  
9 i, t! T5 k% c; C2 b           $fields = array();  1 ?( l2 [5 y4 s: Y( k
           foreach($data as $k=>$v) {  $ @% K5 H8 R0 Y8 a1 o
              switch (substr($v, 0, 2)) {  
% \2 C0 Q8 S4 W                  case '+=':  
6 D! P. i4 [) i. B. B/ H                     $v = substr($v,2);  % j8 f3 I/ X; k  Y$ W6 K
                     if (is_numeric($v)) {  
/ w' ]6 ]* ]) e                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
% t: r% B* {  J: n$ |& N# \                     } else {  
3 Z; `1 X, [" \1 X                         continue;  
* o& {8 y5 G) }& T                     }  3 W& X! I5 {; }! ~- C# v  o
                     break;  1 _$ \8 Q- c3 l5 G" h
                  case '-=':  % D  V  M# U+ x. z, @, V: i" z& n
                     $v = substr($v,2);  
1 b' a: x2 n* Z                     if (is_numeric($v)) {  
: H" p6 B- b# v& u- X                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ( l/ m$ \7 l$ k2 L/ G5 K
                     } else {  $ ?5 \/ q. }/ h! O
                         continue;  
" L5 g3 `2 y  f! F. |                     }  
: V, o; m- [3 K+ E2 w: R                     break;  
, K- Q4 d$ g. O) m                  default:  & N& l2 M7 X9 M0 e
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
) r$ c' r' K% I4 C0 p$ l# \3 T              }  , ~0 c( `! d' g
           }  ) x  ?: F% B% B. H
           $field = implode(',', $fields);  $ P+ |1 k$ b7 ], C: q
       } else {  9 S- z# w4 t' _( U' O
           return false;  " k9 S. \" G  T( d/ Z- H5 G3 w
       }  $ A; U! w( T5 I+ e8 u# b; |
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
3 u# P7 O: ?2 D) x7 u, B+ p! \1 D6 F       print_r($sql);  
: ~( v  ]. R) P% t8 J% Q       return $this->execute($sql);  , @) O" e( [/ i" p# }$ S+ E8 R# X
    }
" y+ e7 W, `1 i从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。8 O5 n1 ^' z9 |) y3 g. F$ c7 d

1 @" C/ w6 v0 e5 u  R4 J8 z攻击测试:
9 w6 k' q% [3 T' z; W5 G" P测试地址http://localhost' O: W: f: {; p8 c/ X
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
7 r2 h3 ~0 T. b3 d! g; Z7 r( j5 o# S+ a* Y

7 N& D7 _) {4 O8 v& L5 j; @" `8 t  |& H7 c2 g! t  W

6 N( x) k0 P- }) A" {4 Q- p. f  e  _# X

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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