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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
* M, F! t( F( `8 H7 q, a漏洞作者:skysheep
: Y/ m7 ~# r/ K- K. _# E: s& L9 A分析作者:Seay9 }! c6 R. u2 w8 ^
博客:http://www.cnseay.com/9 ~' Z3 u: w2 o
漏洞分析:
. n% [: X* }2 Q5 @6 j; P  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。7 b& B8 W% d  s1 ~3 T: j

5 @% s% b; H) P3 J4 n& x% A4 t" E' Q$ y. F
' J5 k- W3 s" m/ D9 z
public function account_manage_info() {  
/ Y% B# B, ~7 {- U! b' o3 M3 a- Q       if(isset($_POST['dosubmit'])) {  & A/ T; }* n! U4 q4 y
           //更新用户昵称  & j5 Q8 a  O$ z1 h- d
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  / o$ y. H5 i( W; g# q/ K
           if($nickname) {  
7 g% U5 x: i3 B% v              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  " m! f( Z% S2 W/ W  y7 }
              if(!isset($cookietime)) {  
4 u1 N( J: b* K                  $get_cookietime = param::get_cookie('cookietime');  + ^  u2 q3 J) c; r9 t8 G( m
              }  
- R5 N0 R. P" z              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
" H4 ?: I* {0 \, d- V" \8 A              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
! L: t2 }6 N( s              param::set_cookie('_nickname', $nickname, $cookietime);  * Y+ F) L/ |6 e5 ^9 }* I
           }  1 ^9 b, T# O0 B# ]# W
           require_once CACHE_MODEL_PATH.'member_input.class.php';    C3 }2 n2 A: S+ @
           require_once CACHE_MODEL_PATH.'member_update.class.php';  " N' s3 O. T: |# X" d. h+ ]
           $member_input = new member_input($this->memberinfo['modelid']);  8 |9 L4 |9 Y; G& O# c" d" C
           $modelinfo = $member_input->get($_POST['info']);  
( l1 K) G2 c( @# ~4 u' w! n" ^9 m           $this->db->set_model($this->memberinfo['modelid']);  , E3 E4 [4 j& T* ]
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
, Y  m  t: G. _           if(!empty($membermodelinfo)) {  " L  T; Z7 @5 h; X
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
* s8 k( g' ?" R! V1 f           } else {  , \% ~% W' J# X1 w5 ^& `
              $modelinfo['userid'] = $this->memberinfo['userid'];  
- Z7 d- ?7 c) ~" q) \) t              $this->db->insert($modelinfo);  
$ H& s7 s; m4 T) p: A           } 6 Y; Y0 p  _; l7 h5 ~" D7 v+ P# d
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,* G7 t: z6 s( Q4 S
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
( {& n2 ?5 x5 @8 @  R, l8 a" s
) O, O, c, n' `, U; d$ {
% l9 s' n2 e; N5 F 2 b/ c# ]9 m% n2 M
function get($data) {  
9 L1 f" n6 H+ X8 N- U2 ~       $this->data = $data = trim_script($data);  4 a  F0 ^2 P* y) S# n; N# ^
       $model_cache = getcache('member_model', 'commons');  
) g5 k2 J2 d5 A& p5 |6 Z. Z       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  0 p. Z) \3 c. {: `* f
       $info = array();  
" r" p* l! m7 [       $debar_filed = array('catid','title','style','thumb','status','islink','description');  * y/ J7 r$ D% `7 z) `' X
       if(is_array($data)) {  - P+ c- p0 p" x5 Z" n/ _! L
           foreach($data as $field=>$value) {  
; d/ U% j1 y9 u& x" u( r4 k              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
  ?9 o, u4 ^! M              $name = $this->fields[$field]['name'];  
. d$ P" V8 }+ H# ]/ p              $minlength = $this->fields[$field]['minlength'];  
( A0 T. _, s7 A" M2 a# u              $maxlength = $this->fields[$field]['maxlength'];  2 L3 m: m6 T0 h$ u$ A8 g* ?
              $pattern = $this->fields[$field]['pattern'];  5 E! Z/ J* C- }+ X7 Y0 E) ]. F
              $errortips = $this->fields[$field]['errortips'];  6 r) H# Z9 z( y# E" _) N4 M
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
, ]% |$ D8 ~5 ~$ q& ]3 R" N; y' h  s              $length = empty($value) ? 0 : strlen($value);  
- L) _1 f1 A& F/ {& j$ F# T              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  7 o: R6 O0 p' y/ N5 H4 ~$ N5 E6 P
              if($maxlength && $length > $maxlength && !$isimport) {  - J' m) |. l9 R) O3 b/ ^; ^$ h
                  showmessage("$name 不得超过 $maxlength 个字符!");  
" `' l) k. q$ E/ a, V6 S              } else {  - c. k/ d1 f$ f2 G. ]5 |
                  str_cut($value, $maxlength);  
8 M, z6 a. R5 A  V* I              }  : y* ?; {' z- N7 `' D: m" Q
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  & _  ?2 W/ J- @: y1 c/ \
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  + R: o; o5 w& h) ~5 V- l
              $func = $this->fields[$field]['formtype'];  
5 d7 Z, p7 r; H9 L# b: @1 o6 \              if(method_exists($this, $func)) $value = $this->$func($field, $value);    H: I- @9 O# G9 C
              $info[$field] = $value;  
7 H3 X7 G) S* T; @# S           }  
/ D, h) ]% ?+ z' a       }  $ o& i" R9 s3 L4 v7 W, ~3 R9 [# ~9 R+ u
       return $info;  1 M( ~. X) j7 B) `
    } * j. o. t  J$ q& K& s6 f
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
- H9 ^; Z7 o& ~3 ]) F) M
* f- K" z5 Y, d7 _' \2 e& e再到phpcms\modules\member\index.php 文件account_manage_info函数
* H& b! H7 }; ~" ]过了get()函数之后。/ v* p. W& y: W, Z- m# l
' {. @& m2 q% m5 @
- L& i* q5 x9 J0 I
$modelinfo = $member_input->get($_POST['info']);  
. ~1 U& J- }1 O           $this->db->set_model($this->memberinfo['modelid']);  
* h% R+ l! u, G. F" Y3 W% n  j# [9 r           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
) M4 n0 H' x" L% Q5 z4 T0 _- ^1 G* C* [           if(!empty($membermodelinfo)) {  , X% t2 s+ Z% F8 w* n5 d, j
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
" _  O9 d5 t% i/ }9 g2 Q0 m3 C           } else { ' ]& H- q' d0 H9 d2 k8 T: L7 ]
直接带入数据库,update函数我们跟进看看' {. z3 Z' _6 {1 r+ r
! a' S# {6 {" B% L/ I3 I# f& w/ M' w

+ b0 W, ~- F# epublic function update($data, $table, $where = '') {  % n% Z, r1 i1 D1 B0 D
       if($table == '' or $where == '') {  ' v4 T4 ^% _& i7 E4 ]" G9 [+ D
           return false;  3 U$ R/ c; j% u$ z
       }  0 ~: [9 \) Z  x* \
       $where = ' WHERE '.$where;  
5 \1 h2 X& a) {, G& S2 K5 I, h       $field = '';  
( C+ T1 Y$ A  V8 r& Y. n       if(is_string($data) && $data != '') {  
, q4 F5 b& \  c. U0 a) b           $field = $data;  
( D! c) K' B7 O9 h' u( C* C3 [& j       } elseif (is_array($data) && count($data) > 0) {  ; }. @# k5 T1 O* Y
           $fields = array();  
' a- j& p" @' J; c! t6 s7 _           foreach($data as $k=>$v) {  
% j6 S' P0 d3 p- B8 I% J              switch (substr($v, 0, 2)) {  0 w% Q+ q7 v9 r; T6 X3 V6 t
                  case '+=':  
! m2 l; e, [5 Z- A                     $v = substr($v,2);  
0 d; v9 Z; `3 G) _! }& I                     if (is_numeric($v)) {  
8 o5 ]% A7 k* c5 o  H                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ( n7 j8 d$ p: A; {) q
                     } else {  
0 _$ r: \7 T: k1 y$ X                         continue;  * I# n% W' O4 Z! I
                     }  
7 e# f: B1 A6 L2 ^                     break;  4 n" \8 L: C0 o! z4 x% w, |2 N& L
                  case '-=':  
3 `; }, F8 _9 M/ N( c5 O                     $v = substr($v,2);  
! V# ], M6 m. g* T. Q$ T* Z                     if (is_numeric($v)) {  0 r/ P0 G( T4 \9 _, @9 {
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
& ~' l* ]3 Q+ X( ^7 N6 ]                     } else {  & G0 L% `0 o4 H& K5 A0 V- Y
                         continue;  
9 r$ L7 L6 E8 D( w% W# N                     }  
* n* ~( |1 E# p1 h8 z7 c3 \                     break;  
$ _1 k/ [6 ^7 a( ?; G                  default:  
7 B0 \' X6 t1 a. G/ {$ ]                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  2 f( f0 ]1 x; S0 w
              }  2 R4 u0 h0 y* f9 x
           }  
" K, j" A, P3 y1 A$ J           $field = implode(',', $fields);  
' H4 i' m" q! z3 e1 K       } else {  " j& k# X& G8 O, v; G+ i0 s
           return false;  * g2 d4 M, t1 Z  z7 V1 P0 p8 T; a0 k2 |
       }  9 Z, a3 z# k9 j6 ]$ [
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  , P( R+ T* ?' a6 |, j( N
       print_r($sql);  ' @6 v# O9 ^  S( W, z% m
       return $this->execute($sql);  ) ^# q2 ]* b$ c% Z8 h) g: u. @
    }
1 a4 n5 z8 y. y从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。8 Y0 U$ X4 D8 h6 I' _& Z

9 ?1 A8 b' o, O' N& d+ R9 `/ w攻击测试:! j) k: ]2 X% M6 {6 t' _" e0 x
测试地址http://localhost5 k* |: f* p0 k
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句  d1 ~  [% t3 I3 c3 _* m

  R9 t2 ~' d6 C# B & d; J  E( j1 F2 f0 U* d
' b8 E/ Z* v( `# g& o9 A: B

2 t* F6 B( J* f" m, k& Q3 k4 k6 T3 }2 b3 f6 D; M8 w; @- Y" C) z

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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