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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告# N+ N+ \# F* S) Y* x5 ^
漏洞作者:skysheep( e/ ?/ j5 F5 s/ [1 L0 l9 i
分析作者:Seay
9 z1 _. _# `* S  X  u博客:http://www.cnseay.com/
5 D+ {/ Z8 ]- G" m7 _9 l0 ]漏洞分析:9 U+ c5 o- h& [4 X' l
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
5 _6 u' d' D( ~7 K9 i. r6 @3 Y) \+ T7 w- P1 l' S

) t' u' G- d6 d, e - o+ h& \* V% u/ H' G3 A
public function account_manage_info() {  ! F* T) ?1 w" g& W
       if(isset($_POST['dosubmit'])) {  
. J5 v$ q6 C+ H3 K9 X% r# q4 g           //更新用户昵称  
- }: u" d7 f. ^' \           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  3 A* L' e, ]# F
           if($nickname) {  
: s7 k" u( r& V# q# c3 ]              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
& T8 R# b- K' u% r2 @; {              if(!isset($cookietime)) {  ; f. Q, L/ @* I3 H( T0 x
                  $get_cookietime = param::get_cookie('cookietime');  ' U9 y8 a- ^9 c  n" m$ w
              }  
9 j0 y. n! m& c! V. @6 ~: |              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
, i# p/ N9 T( Q  ^8 z- ^& A6 c4 o              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  : Y6 b& P4 |. {( A
              param::set_cookie('_nickname', $nickname, $cookietime);  
; ~; f& S4 Y2 Q& \9 m           }  
6 q# O. I6 {2 k( S) p$ ^           require_once CACHE_MODEL_PATH.'member_input.class.php';  " p4 |) M, Z( d1 ?9 S# ?
           require_once CACHE_MODEL_PATH.'member_update.class.php';  9 [+ ^  I. g, {
           $member_input = new member_input($this->memberinfo['modelid']);  
9 }2 [, I1 ?( R8 \/ k* e% ?           $modelinfo = $member_input->get($_POST['info']);  
: i/ @$ H: |6 H9 j* X4 Q! l# E           $this->db->set_model($this->memberinfo['modelid']);  8 Z) r! r. d; q7 t; R9 y
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  % a& G- ?& G/ q8 b7 m
           if(!empty($membermodelinfo)) {  
; h: [" D7 X9 x5 R              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
. [2 a( f+ \4 X: h2 j/ E+ r. @           } else {  " y. m# Q" Q- d9 \2 U
              $modelinfo['userid'] = $this->memberinfo['userid'];  8 c" m. [( ~7 x% H5 ?! \: g
              $this->db->insert($modelinfo);  
1 C1 a& l3 D. P( u/ l8 Q           } ) P" \; R* `8 q2 O, A
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
: g4 Z* d6 d/ P% D5 S" x在\caches\caches_model\caches_data\ member_input.class.php 文件中:+ |& I9 V- m! f  m0 n5 q4 G
- z/ H8 Q: v, x$ f
/ t/ s! F1 s+ I% Z

) y) q. {* R: Ifunction get($data) {  1 j, G; Z4 m( B) ^" `, q7 B* a
       $this->data = $data = trim_script($data);  + A: p3 d* e# ~( Y" n8 g: D3 z
       $model_cache = getcache('member_model', 'commons');  
/ v' G5 |  c4 f2 m- F! }! ?       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  ) ]; M, E! T# N1 Q+ S( f; F+ s# B
       $info = array();  # d# N4 a0 D) q
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
9 B- Q9 B% |8 m3 v, g# k       if(is_array($data)) {  4 V9 v5 u2 G3 k+ z
           foreach($data as $field=>$value) {  
3 w2 j9 w1 r8 A/ R              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  % i* ]  G) s) `; ^3 K& m
              $name = $this->fields[$field]['name'];  8 ?1 D) k$ R$ X
              $minlength = $this->fields[$field]['minlength'];  1 K! ^  F. X' L0 S8 g- a' ^
              $maxlength = $this->fields[$field]['maxlength'];  
7 [& v* [$ s2 G# e* Q: j, n9 n              $pattern = $this->fields[$field]['pattern'];  
$ Q6 o8 `$ E0 l: q+ j              $errortips = $this->fields[$field]['errortips'];  
* M0 ~0 H, J5 s' i, y, S              if(empty($errortips)) $errortips = "$name 不符合要求!";  
5 @" y6 p7 x) {5 h( n: L: E              $length = empty($value) ? 0 : strlen($value);  
; G) m9 e$ ^5 ^( I& }, O/ S! J              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  7 p$ H( E7 Z; v! ^( }
              if($maxlength && $length > $maxlength && !$isimport) {  2 E7 I, v/ o/ f
                  showmessage("$name 不得超过 $maxlength 个字符!");  
: s" Y, M  a$ I; z! r" J2 h              } else {  " |8 W3 A+ m/ g9 X% k6 S) O
                  str_cut($value, $maxlength);    d2 {( k6 s2 @) w: a2 @( f
              }  
# n5 F9 l2 J! o( n  x              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  # e* G  L3 p( y. B) \& ?
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
/ Z; n' _- E( t/ E4 _4 J              $func = $this->fields[$field]['formtype'];  . h5 j3 f% ^$ c+ J& z# s& [
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  5 S& f; r7 r9 b( R( S4 ~0 z
              $info[$field] = $value;  
/ b) _# D7 Q) z0 G1 r           }  
8 D  K: p+ i3 z0 ^4 p/ d+ F; X- b       }  
, p8 V0 e% l. n; f. |       return $info;  
; X# [" @8 L* R    }
. H- T$ y6 Z7 K/ B; E9 [trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,3 p1 {' d- T! e$ v( c6 {

4 t. S5 V6 @1 o8 r  ]2 c  b+ x再到phpcms\modules\member\index.php 文件account_manage_info函数
: ]- x  ^( L3 L% q% S/ H过了get()函数之后。5 A0 M6 X9 c1 A; X4 z: n) W: m  Q0 D
$ h! m2 I& b7 ?0 X; u! ^

5 M5 `0 }+ E/ Q) p# c( M( k/ b$modelinfo = $member_input->get($_POST['info']);  
8 a) L9 @) P, a" x" n           $this->db->set_model($this->memberinfo['modelid']);  
+ ]. Q! \' @# y- j           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
6 }5 Q9 G, W1 Q) \+ o5 u           if(!empty($membermodelinfo)) {  4 X# H; i2 ]1 D8 A  H  @. A
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
3 k4 ^/ `5 |: j           } else {
! L$ L" C" C* H+ }3 O. E8 o直接带入数据库,update函数我们跟进看看
1 k, I5 m; a3 q/ l$ r% ]) C8 {4 U+ V- I5 Z

6 R. F" e- y9 \- \public function update($data, $table, $where = '') {  
/ r# T  x) c1 p  i       if($table == '' or $where == '') {  # W1 l# Q+ P2 z) b& {* I& b
           return false;  
. T* T( f( F! b" p1 H, v       }  
! [& s; w( f$ C- d: i5 j       $where = ' WHERE '.$where;  7 ~8 J$ j* E2 {3 a; ]
       $field = '';  
3 |* ]0 X  C% _2 F/ O" Q+ ^       if(is_string($data) && $data != '') {  
- X4 w" _4 z. g& `1 g: V8 n5 r           $field = $data;  - s- z) P6 @: ~' Y; N
       } elseif (is_array($data) && count($data) > 0) {  ! e% Q9 P$ e, \
           $fields = array();  3 ~+ d# Z0 }" o6 o
           foreach($data as $k=>$v) {  
) s. [% ~  d' u' n$ D7 a              switch (substr($v, 0, 2)) {  
% Q7 P+ g7 F& d  }& i7 Y- X                  case '+=':  0 }/ _# x& B% l8 i$ H$ i) ~& x
                     $v = substr($v,2);  # o0 x7 j" g) Q* N
                     if (is_numeric($v)) {  
, U) |8 H- Z: k1 @# S1 w                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
1 t6 x, K' W% w" W. h6 T/ P                     } else {  , y8 ]* j6 X. ~2 ]1 _% u
                         continue;  5 e9 _/ Y2 K# s( ^4 V2 p& _( W
                     }  
* C( _5 `- h% U- I+ U                     break;  1 s, x, L; H3 `5 W: Y2 p1 P
                  case '-=':  
9 L2 Q) k3 s1 g( D                     $v = substr($v,2);  4 c# g" X" ?; h9 H
                     if (is_numeric($v)) {  ' }+ S8 W: ~7 |1 a
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
) Q. V# v* z$ X! S$ A                     } else {  5 S0 _' f6 v" w6 N6 P
                         continue;  
" _% {+ I' u4 t* n6 h                     }  1 J4 e% d8 a( |2 K! X
                     break;  + B; L, y2 M5 w
                  default:  
3 H0 A3 M/ v! U1 Z1 j7 e                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
1 t, L8 B* {1 z6 g8 W  D4 r( X+ H0 _              }  
2 s4 K5 v# U% h7 c           }  
$ a$ O4 s" \+ z$ h: o  T6 i8 @( d           $field = implode(',', $fields);  
' G* {) Y, s  {2 d3 Z5 y       } else {  1 k) ?# a: C3 x" B* u: I
           return false;  1 b9 a$ H$ v/ Z* j. P/ Y
       }  
8 A4 e4 S* \6 Y; O; n       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  3 h1 y, y9 y( _: \
       print_r($sql);  
" a3 I. X; G5 o6 C3 R4 i  Z: n       return $this->execute($sql);  
, ^1 T; k* z6 ?' j    }
; X4 M( x. D* d) U4 T" |  ^3 p0 i从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
" Y9 c  [- F6 h% Z' a
, }2 `* ^2 E) L) T* y- a! k攻击测试:; Q& |& m8 g4 ~) U  d
测试地址http://localhost
* m8 _: p' I6 U7 @% O  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句) j& ^+ r( ]! Z9 X" U
2 C* O  M% N. W2 h3 }
" H, @0 {4 A# k# V
4 R0 S$ i8 _- Z% }

0 K6 c! u; T3 [% _1 y6 w( `
- i% j: h& N4 n% e+ M5 ]0 Q

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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