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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
$ m4 p  M: ?- j+ j" g" ?, F漏洞作者:skysheep
* Y( u4 _; E( B7 i  s% I* `分析作者:Seay
0 [) t8 d/ E- v; q5 a6 d7 k4 X; r1 v博客:http://www.cnseay.com/. g/ @% }7 Q% i
漏洞分析:
/ n! i. \: W9 o  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。% V8 f+ T6 Z' }
, |0 X4 P# s2 v; {3 D* z/ ~0 a- R
% g) B) f  v  K2 I# D& Q3 C$ {0 }! V

" Y% ~6 A7 ~" u6 ]3 p1 q& [, ]4 Dpublic function account_manage_info() {  % O2 \; B$ l1 c% e
       if(isset($_POST['dosubmit'])) {  1 k* U4 `6 r3 `& ?; u% c( F% V
           //更新用户昵称  
3 }3 A4 k, e. [! h% h5 T% q- q           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  / P* t/ m* p9 H$ z. Z, C5 e
           if($nickname) {  
. E# M, C$ K9 z+ t              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
( ?) q7 U, o" M. L9 _              if(!isset($cookietime)) {  2 {8 _1 v0 E& \3 R
                  $get_cookietime = param::get_cookie('cookietime');  
; Z! X( c2 C5 v! U- _* y              }  
9 i4 }  d1 U  M7 e: D. G+ P6 K              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  & I& E  q1 p& `- [) z
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
6 L  j$ m+ S! K4 {              param::set_cookie('_nickname', $nickname, $cookietime);  ' Z3 @# O& h6 d
           }  
0 S: j" K6 @( H- x: q/ u; O( m, J0 [           require_once CACHE_MODEL_PATH.'member_input.class.php';  3 Z4 j+ P1 Q1 x% \1 H9 U, n8 B
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
; S" W% S& Y; L) g, \. z/ k           $member_input = new member_input($this->memberinfo['modelid']);  
% a0 A; ]3 ^. H* ^           $modelinfo = $member_input->get($_POST['info']);  
. f8 ~4 \0 S1 u; }# X3 J! ?& g           $this->db->set_model($this->memberinfo['modelid']);  
& B( V2 {! H- ]! C: v- x) C           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
5 a( x  [& B4 t2 L5 F           if(!empty($membermodelinfo)) {  / l8 k' _2 P) T. A. N) k
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  9 Q% _( o9 y1 B$ v& A
           } else {  
) P3 g/ o' J' Y: ~              $modelinfo['userid'] = $this->memberinfo['userid'];  
# F) G& M+ ]2 Z: P# m) V7 f              $this->db->insert($modelinfo);  & a5 r: |: y2 c' B5 c0 l2 y% c
           } 1 C+ B9 g7 I( H
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,* M% o! |$ \( j& f7 c6 K
在\caches\caches_model\caches_data\ member_input.class.php 文件中:' B* w9 m0 A) `' m
# A# O: a! Z5 u$ E

: {, U2 x# a4 B$ A, X1 p/ e ( A! A( K5 [0 ]
function get($data) {  5 f7 F; x$ B, e+ ^1 T
       $this->data = $data = trim_script($data);  2 v4 ~. f! \) o3 [
       $model_cache = getcache('member_model', 'commons');  
( L2 e! ?8 [7 g6 A1 \1 ?1 _7 R       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
2 j! l& M# @' [4 }) {2 s- t7 O  {' c* ^       $info = array();  
, `- ?2 k% w' V       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
9 X5 |6 }* y4 {! u: C4 G5 ~       if(is_array($data)) {  ( H2 s6 d$ L, n  L+ x% s
           foreach($data as $field=>$value) {  
  Z; s% Y  r' {& G3 J0 j8 l8 l              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  $ H$ h2 C+ |0 r. N  F3 C$ L" l
              $name = $this->fields[$field]['name'];  ' b% z7 y5 X" b; i+ J  A3 N4 `& ]; P
              $minlength = $this->fields[$field]['minlength'];  
+ I2 d+ v$ U2 k9 g; O- _" h) a              $maxlength = $this->fields[$field]['maxlength'];  
/ j" D! T# K5 B4 H: |# f              $pattern = $this->fields[$field]['pattern'];  / D+ z8 P( `* A1 @
              $errortips = $this->fields[$field]['errortips'];  
' }, M8 e2 o0 l6 _) _" m              if(empty($errortips)) $errortips = "$name 不符合要求!";  
. i5 c' o" X4 @7 F  n$ X3 D              $length = empty($value) ? 0 : strlen($value);  - w& ^5 Z& x. b* F0 G$ u
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
, _8 h9 @1 X8 R              if($maxlength && $length > $maxlength && !$isimport) {  
$ C) n$ ~2 [( G/ N2 E2 I                  showmessage("$name 不得超过 $maxlength 个字符!");  
3 M) n8 R- `8 ]+ n, O( Q              } else {  
9 a( K- p( U* F0 w, L+ O                  str_cut($value, $maxlength);  
' n" i3 V% u2 l              }  
- H, R  W( a8 K- h              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  3 e) y1 X  J/ A1 l0 E
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
8 Z# K( ~6 I' `, L# w! f, @              $func = $this->fields[$field]['formtype'];  
8 w& m; c3 V% l% [1 z5 B/ S              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ) }$ c( v( j+ ]5 h5 L3 `; w7 D
              $info[$field] = $value;  . N( x2 n7 a. r6 i/ p& E* z  [$ D
           }  5 `$ G3 ~. n7 ^
       }  
+ t6 B" D" a7 K+ E6 b# O       return $info;  ( |- T% R3 V& G3 R* F  l0 X) l
    } 9 U! C- W0 e9 U
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
) ?) C9 l& y- y% |7 p9 V) g1 P; N" A0 d9 P
再到phpcms\modules\member\index.php 文件account_manage_info函数
5 Q9 x2 O3 M8 G& i3 m过了get()函数之后。
% d, A" ]( z4 v! [2 f8 F* u0 S$ q( i6 ~' v$ F
' G4 [$ c. U4 F7 D
$modelinfo = $member_input->get($_POST['info']);  
! R; L% M# m7 E; g6 J2 j           $this->db->set_model($this->memberinfo['modelid']);  
+ n+ f( f- `8 ?           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
% k( [% S( S3 z2 D5 }6 _' Q3 ^           if(!empty($membermodelinfo)) {  ! L" [& ^* v5 Y. `
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  : i2 ]/ ?. T# U) j' h. A: Q1 m- I
           } else { , t; g0 @* }$ m( k( K  `/ q3 x
直接带入数据库,update函数我们跟进看看' U; E, \) \7 R

4 w" q0 M# Y" c6 O% _8 Q+ o , I: ]1 l! {$ @7 ^$ P+ U+ @
public function update($data, $table, $where = '') {  1 F* f9 H: a: G% K5 O' _
       if($table == '' or $where == '') {  
2 L$ b( Y6 u0 [( e- s$ T7 U8 @           return false;  
: J0 S* h4 a# @' M3 O       }  
5 q, }! \& @: I, X       $where = ' WHERE '.$where;  
4 }4 T6 f+ f: {& }; R* Z4 e6 a- e" p       $field = '';  
7 g7 j7 R0 S1 d* k9 U       if(is_string($data) && $data != '') {  
& P$ V/ j- @+ _8 g3 V6 M( s" L           $field = $data;  1 u( _4 g1 A1 @+ i  w" _6 ]5 T3 [: w
       } elseif (is_array($data) && count($data) > 0) {  
( }/ I& h2 I0 o( ?+ ]           $fields = array();  
1 r3 H9 m* l; T           foreach($data as $k=>$v) {  
2 E! s/ m: I3 y" S& L2 p              switch (substr($v, 0, 2)) {  ' x( Y8 @5 k0 Y9 d) O" ]
                  case '+=':  4 W; K9 P2 y5 g- u2 O8 M& N
                     $v = substr($v,2);  6 Y* q( `3 y3 F. |; o
                     if (is_numeric($v)) {  
8 ?/ c7 p, k% r6 R; i                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
2 f! ^6 _! x4 R0 p                     } else {  # @7 ^: D  f8 |8 v; `) ?
                         continue;  
6 g, S: ?1 }' w4 {. Y                     }  
% \: M4 d8 f8 K% l8 U/ W. T8 r                     break;  2 j. P% y+ u7 W2 B1 c# m& x! W
                  case '-=':  
+ _. ^1 H/ A0 t1 O0 I% V& |                     $v = substr($v,2);  5 c, x$ T" p5 V/ B5 z# Y( @/ B
                     if (is_numeric($v)) {  
3 _# E% w! h  R$ D7 J6 f  c2 b3 P                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
* i" r- d0 P1 _5 j# \7 _6 d                     } else {  
8 v, j# u% Z- ]7 U                         continue;  
9 d$ G+ m5 m9 g3 A% ]- z                     }  
/ R% m$ ^( `( h/ U3 p" i" w+ X2 B                     break;  
4 C2 I; Z9 X; B                  default:  
" b# U8 w. {& |. J0 I& [' M% L( t5 @                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
/ |3 X9 y# h, w. i- A# j# i              }  3 q4 n! Y$ Q+ R% [8 E
           }  : P+ \2 |) Q/ u# q. J4 O& k& R
           $field = implode(',', $fields);  + Z; o3 m2 K- |, R% q8 \0 Y
       } else {  ! _9 H7 v% A/ \: n7 C( f
           return false;  $ [( E7 ^4 X0 p7 M9 n+ J
       }  
2 \8 J1 L& {) z7 q       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  9 N  M! q9 G, c
       print_r($sql);  * W0 w6 W9 m! Q8 V0 A: U
       return $this->execute($sql);  
" B2 [/ U: y# q- p! q! d/ f3 p    }
6 @' X" e9 a) i9 @- R从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。; V* W8 z# H0 b& t" h

2 T8 H6 g2 I" P' B1 ^攻击测试:
2 M+ J* Z1 c' q. v9 m测试地址http://localhost' V! {, k( p0 y! G3 I2 N
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句" a' f. A+ U  |) r, a5 ^; p
+ D; a9 o) c9 a" n& {

8 s3 U: ]# }+ O! h
3 S. S6 }( i; [3 v7 ~: x! @! x9 [* O6 k
2 E/ x1 c) t6 [0 N+ l& x( k$ K1 W

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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