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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告% y/ g  f9 |5 d! `
漏洞作者:skysheep
' [1 n* u5 J. m2 Q, c4 f( `分析作者:Seay
, i/ l$ d# I. W/ }! w9 F博客:http://www.cnseay.com/$ U  I7 R. f( p, E
漏洞分析:5 X; b' [. E- a5 {1 |+ c
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。0 m3 l1 B) r/ n/ b6 l

# \0 W& R/ p) l. o8 F+ }
6 F: {: [0 P6 l& W9 D( D; s
# G4 p- R+ o! l& o! R0 I2 Jpublic function account_manage_info() {  
% V7 r* n% p0 [) N7 P; q       if(isset($_POST['dosubmit'])) {    v7 ~+ }6 D5 I6 ~* ~: ]
           //更新用户昵称  
1 b( N, M. \: [8 U; n* `; V# `           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
5 G0 M4 j% G2 m) @9 T0 c           if($nickname) {  # I7 D9 H( L) l/ i4 L
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
  T% m2 i) @; Q0 k& Y5 D4 S# j              if(!isset($cookietime)) {  
, g, c4 a6 q! W5 H; c                  $get_cookietime = param::get_cookie('cookietime');  7 p! K' C8 L; G
              }    [! H' \# e  {& m- \' C
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  3 ~* F5 ?, X8 {9 S6 ^
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
  w9 H% q5 e- v, k              param::set_cookie('_nickname', $nickname, $cookietime);  & j/ \0 C% L5 ]0 q
           }  
0 D/ Z3 U. ^% ~2 s& K           require_once CACHE_MODEL_PATH.'member_input.class.php';  % a; U" L; M0 v2 h& \
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
) l* y3 R; @; y( U           $member_input = new member_input($this->memberinfo['modelid']);  / d' @" ^  o3 c  `
           $modelinfo = $member_input->get($_POST['info']);  
- c' Y) x5 M( n: ~           $this->db->set_model($this->memberinfo['modelid']);  & `$ T/ N' w9 G: f6 A3 H3 v) Y
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));    F7 ]" ]: I9 @0 E. n3 c
           if(!empty($membermodelinfo)) {  # h7 O6 S1 ?6 `3 U+ J* P. E
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
9 [- V4 U) c5 z  `9 r% p* n' S* ]           } else {  0 ?8 L7 M* y* q; N+ y4 S
              $modelinfo['userid'] = $this->memberinfo['userid'];  + ]; O% l; I$ i8 ~7 T& V6 Q
              $this->db->insert($modelinfo);  0 N3 P$ H* [/ C5 V0 g* N) ]( g/ o
           }
. D( Z9 B' b- D. W代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
9 Z6 |; ]) Q) ]# @在\caches\caches_model\caches_data\ member_input.class.php 文件中:* M+ t# f$ `' g1 s
  I. C0 m3 e( @7 c2 S
4 L6 y" d/ i* W0 p( e) R" h
+ H1 M# h- M# Q' ?
function get($data) {  , ~) q* g% U5 n2 R2 v' `: J  d
       $this->data = $data = trim_script($data);  ) {, N- H$ ?, J+ ?
       $model_cache = getcache('member_model', 'commons');  
  t' p" Y, m6 G+ P( @       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
0 h: P6 O2 i3 d  i9 u       $info = array();  . Y* ^  P/ m# H
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
! {. s7 U9 m3 ^       if(is_array($data)) {  
  s. {, y* J1 v* T% h/ Z           foreach($data as $field=>$value) {  
3 x; q& E. L# j: F2 |  E              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
# I1 @/ k  k1 {7 `              $name = $this->fields[$field]['name'];  
' C5 a& }( I( A- P/ `, U2 X0 z              $minlength = $this->fields[$field]['minlength'];  
+ x: X7 _6 o, j# h  O) ]              $maxlength = $this->fields[$field]['maxlength'];  
3 a' [1 j+ \4 k0 L  W              $pattern = $this->fields[$field]['pattern'];  7 {1 D9 E( ]9 i4 u7 h! \/ Z
              $errortips = $this->fields[$field]['errortips'];  8 M  G8 T( W1 f  k* w9 F
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; _& ~) H8 @0 c: \              $length = empty($value) ? 0 : strlen($value);  
: X' u* L; n! |# i6 g' k, Y: o) ?              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ( n' s5 S) ]4 b
              if($maxlength && $length > $maxlength && !$isimport) {  
& \; p/ R  L' z& a, u4 D                  showmessage("$name 不得超过 $maxlength 个字符!");  
. U9 @9 ~4 |- {' O5 Y! T0 i9 Z4 ?+ o              } else {  4 z+ x! c( t8 n$ u+ S7 ^$ \7 B  _
                  str_cut($value, $maxlength);  5 Z- g  N9 K6 p
              }  
$ D# c2 D* T. Q  G; B              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
* d; S7 m2 t' W! }" C1 h+ h                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  * X+ G0 m' z( w
              $func = $this->fields[$field]['formtype'];  
& E" L$ b8 u% o! R' H4 c              if(method_exists($this, $func)) $value = $this->$func($field, $value);  3 r5 a( u" k+ r* F
              $info[$field] = $value;  
, [& u1 x& I9 e6 i+ i           }  6 m' |7 b; k6 s9 i$ `  [( ~* ?
       }  6 T2 K" M6 ~- O; p* p
       return $info;  - H/ m' }# X8 h6 Q# e3 ]# g! Y
    } % o) q! r0 b7 B5 Y- W6 _) R5 z; _" G
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,& f) f& a( R0 U: }+ q- G6 \
3 J% P1 O0 G0 x  X$ ?
再到phpcms\modules\member\index.php 文件account_manage_info函数4 A" \' P0 d8 V
过了get()函数之后。
3 Q/ I7 J8 B5 {) a
; C/ `) b; K3 I6 U$ U* C6 q
. A; H6 f% d' [$modelinfo = $member_input->get($_POST['info']);  
2 }  H- B% Y/ J0 m' H1 |& n2 C* M           $this->db->set_model($this->memberinfo['modelid']);  
/ N. g3 h& C9 j2 N           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
1 u  U1 `! `  h( J$ |2 e           if(!empty($membermodelinfo)) {  . Z" ]9 Y9 n" H
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  4 }6 P  S7 G4 K2 c- g. F/ V. Y; Y
           } else { 5 f; t5 Q6 r: t
直接带入数据库,update函数我们跟进看看1 X+ X" I. [6 e" q
4 q+ V& w. f! U) k" j. h+ u+ k
- W. N6 b% n2 |' Z6 x9 @8 X1 [/ v" w6 a
public function update($data, $table, $where = '') {  
3 a: D9 B' U. w/ K4 j4 o( e3 S  M       if($table == '' or $where == '') {  
9 i' ~9 H* M( ]0 A5 `- j; y           return false;  0 @) x* J$ J, F4 s
       }  , `, n: j! t& J) ~
       $where = ' WHERE '.$where;  
- h+ [" b" x: f0 N% M' M       $field = '';  
6 w. p6 @# W' u6 P       if(is_string($data) && $data != '') {  
7 k2 t/ L$ ~+ m4 X' B/ s           $field = $data;    Q5 P' q9 F2 g3 }
       } elseif (is_array($data) && count($data) > 0) {  ; t! n7 r. w1 r  k6 @
           $fields = array();  ' H$ ^+ X4 L0 r$ T. u6 r7 x  x
           foreach($data as $k=>$v) {  - \7 t5 l4 ]$ ~+ C
              switch (substr($v, 0, 2)) {  
" i( m& t' o1 D. F' o. l# |                  case '+=':  
3 X% K. B  J+ Q$ t  m/ O! v; O8 o8 S                     $v = substr($v,2);  $ N: _, @% B6 V' k2 Z  `
                     if (is_numeric($v)) {  
9 X! j) r4 t3 V                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ; T) B9 f& b/ A0 |
                     } else {  
. ]9 l- T8 [& k+ V( A) W                         continue;  
# l. t* s+ O5 K# Y                     }  2 B' ]0 Y3 i- z- \6 ?# e6 ]* `
                     break;  $ H# L2 [5 k# V$ Z4 _* ]5 w3 s
                  case '-=':  1 _7 B; p4 z, t- L4 D$ I! s& W' L7 y
                     $v = substr($v,2);  0 J- N/ G2 n% t& z/ W
                     if (is_numeric($v)) {  * p4 [6 S! P1 u; F. O5 w. J& B- P& Z
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  6 f& `6 r! V# [$ [0 M  D% I1 P
                     } else {  1 }0 M4 i3 o, @2 m. i
                         continue;  
2 W1 Q& @( G: `* M1 N  l+ s                     }  
1 R* v  [4 X3 w; b                     break;  
/ [. y+ h2 D  c                  default:  
/ [$ F0 b/ Z% o  E9 x' o, b' @                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
2 h# ~% v6 Z8 d- N              }  ) h; j. j% s' q9 Z" n
           }  
! O# O& b0 O- u3 V" H5 W           $field = implode(',', $fields);  
0 X- r0 x; W8 C2 X0 T: d$ L: ]       } else {  ) a# E% G- {. `, c0 |
           return false;  
' X# m7 n, N% O8 k       }  
. C  N- ~. y+ l9 F       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ( Q: o% M" q& W# ?9 @( Q1 b. H6 x
       print_r($sql);  
2 ?: l; W1 o2 b; m1 q9 a       return $this->execute($sql);  5 U# m! c4 a# g0 x* p
    } ( K) q, j: `6 V4 |4 b- ~0 d
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。$ j6 n  P( z" i
4 l# i3 r0 b) H
攻击测试:
* B) i7 p" x; v/ A% o7 S1 U- l测试地址http://localhost
+ Y1 g# J. |) N/ [# |  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句3 r* k8 Q! ~# [0 q! J7 l
* h& e0 D; ?( J

/ S/ d& ~3 [2 m. j7 P
2 q+ b0 `4 m0 [* P$ |8 K1 o3 L+ H6 t
$ z9 x2 e3 X& d- R

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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