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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
+ D; Y+ H, C8 F7 z6 {9 i" Z. p漏洞作者:skysheep1 L, s$ [1 }* m% i
分析作者:Seay; P( B/ b) |3 N
博客:http://www.cnseay.com/% e9 P) H% }& w: N5 i! A
漏洞分析:
7 u5 s/ r% N2 `& a" S( d4 s* \  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。6 a! `! I% e" u- f& k

% M# H( C$ T7 F& A, v7 L
  l1 Y( s% `8 l+ z' y8 ?5 h
4 M# s$ }4 o4 T6 u: {- g- V) j$ T) Ipublic function account_manage_info() {  : U, j4 V- o4 ?3 U: I, @
       if(isset($_POST['dosubmit'])) {  
* c1 Z' F( [$ L. q           //更新用户昵称  $ m& X7 Z  y, e0 w, K
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
. c7 `6 W( d; r( E5 {           if($nickname) {  
) b7 @( ^* i6 v0 v# a% S9 R              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
8 u: g# O3 W2 t# [+ U9 \  Z              if(!isset($cookietime)) {  . ]2 J; B! Y% A/ \& |3 l2 P3 U
                  $get_cookietime = param::get_cookie('cookietime');  
. i$ j8 s5 P- O3 O4 `7 e+ K1 H1 _6 }              }  
* M9 ]: f! C; n4 ]* c              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  ) @6 P% ?, n$ a3 a
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
* P1 b# H6 Q: t/ M4 C              param::set_cookie('_nickname', $nickname, $cookietime);  
, @7 Y: H  z! a7 B           }  
5 b: Z. m3 l/ w0 Y           require_once CACHE_MODEL_PATH.'member_input.class.php';  ; P* o) b; O5 T
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
1 w' R& X2 k2 p! P           $member_input = new member_input($this->memberinfo['modelid']);  ! z8 A( Q2 G8 _3 m
           $modelinfo = $member_input->get($_POST['info']);  
9 ]7 S) l) z: J+ [' }# {  i           $this->db->set_model($this->memberinfo['modelid']);  
- z$ o6 V  }' x5 f! c5 ^) [( a5 j           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
, l- l1 W) d4 R  V8 \           if(!empty($membermodelinfo)) {  
9 _6 n, J9 G; n0 A" _, t6 H' n4 a" ]              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
: W( b7 T  M; \3 s           } else {  , k; ?8 a+ `! |. M2 t4 n% s, p
              $modelinfo['userid'] = $this->memberinfo['userid'];  , [- `: K/ P# x% I) k
              $this->db->insert($modelinfo);  
! W5 R# ~4 k6 U           }
6 O! E  `2 e. J. N4 @8 C. r; B: u代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,& v7 [" w; n+ g! o; `' h7 i+ U
在\caches\caches_model\caches_data\ member_input.class.php 文件中:4 P" g! \' \( B+ C; [3 x6 A
5 x4 h* @0 \2 R9 E; t. n
1 l" @, T+ E6 F5 t* f; @

1 i. `, Y8 w% Mfunction get($data) {  
" r' k2 w4 Z+ b5 Q& ]8 `  I       $this->data = $data = trim_script($data);    I, Y4 u7 z. r5 }2 ]
       $model_cache = getcache('member_model', 'commons');  $ `# i5 i( \5 g1 n2 ]
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  ! r$ e9 |4 D8 ~
       $info = array();  
% q' S6 t9 [) l# N7 o( t/ w/ t       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
" c" H2 V# p% ]. s- G4 W$ I0 q4 s       if(is_array($data)) {  
! Q) N0 A  V  M- k9 w( c           foreach($data as $field=>$value) {  
$ m1 z" r; o* i6 @              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  & n. I2 Z, S. g9 m" B8 Q
              $name = $this->fields[$field]['name'];  " N5 u7 `$ X- _: U. `4 j  W
              $minlength = $this->fields[$field]['minlength'];  ! T2 {# b' @$ q4 }
              $maxlength = $this->fields[$field]['maxlength'];  3 e" X# D) L6 K' d
              $pattern = $this->fields[$field]['pattern'];  + w0 A) H7 r  s5 x7 t
              $errortips = $this->fields[$field]['errortips'];  
+ J" B5 n1 ^3 w& _$ c( D              if(empty($errortips)) $errortips = "$name 不符合要求!";  , V; x# ]7 }! s5 ]4 \. [
              $length = empty($value) ? 0 : strlen($value);  
, e6 E) C# G: L* d# Z# o) m              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
- R# A: |# \4 j0 g* N' C7 Z8 a4 @# _              if($maxlength && $length > $maxlength && !$isimport) {  
! @, \$ A; Y- y  c                  showmessage("$name 不得超过 $maxlength 个字符!");  ; E7 p4 _7 A# |; E* N
              } else {  ! E  Q$ n# n' A8 f
                  str_cut($value, $maxlength);  
2 v, ?5 G+ C  l, O" m              }  , j0 |8 v: i* x( k/ Q- n
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ' W8 @6 f6 J+ O( \. ^
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  - D8 [4 E* S1 t3 |: w
              $func = $this->fields[$field]['formtype'];  + m1 d' Y: C; w% A! H
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
% s( z9 Y7 p2 o  H7 O* \              $info[$field] = $value;  
! h7 X- S6 g7 V           }  
; Q) U" i' t7 P, Q! r       }  , v" Z4 Y& N, g' T& m+ @
       return $info;  
( P- H7 ]5 _3 j2 k  U) E    }
7 r/ H4 V, c2 n9 a# p8 p( g! Itrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
: t. _5 s" Y" _: @& @/ s; Q, m# B
再到phpcms\modules\member\index.php 文件account_manage_info函数0 n' e$ B4 r7 _- N- r9 d
过了get()函数之后。
# B- X2 W3 U: j  t* R, f4 O6 }* w1 ~4 c( U* Z
8 Z$ c. n2 x, W4 D
$modelinfo = $member_input->get($_POST['info']);  1 m1 H4 [- @1 p, g, H; R
           $this->db->set_model($this->memberinfo['modelid']);  & _, Z- F; E, f( ~( E
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  8 W% \: W2 y- n9 L; O
           if(!empty($membermodelinfo)) {  
# _; r$ w6 [* z8 M+ g, O              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  7 V  Z: k2 b, {4 O3 w, F( t3 X$ g  R
           } else { * S( f7 Q" T; m2 p: w& B% e( v
直接带入数据库,update函数我们跟进看看
9 ]' U# g! Q, R0 v/ s2 h
9 m$ q; @5 J+ A5 Q4 u' d. v
0 E. D# L( }" Bpublic function update($data, $table, $where = '') {  
, ~9 X: r  H5 c. m% `       if($table == '' or $where == '') {  
! h3 s% C$ `9 [( V# p5 p! V4 D& ~           return false;  & _0 I6 \# ?* k5 R
       }  
8 h7 T2 y% A: ]6 A1 ^4 B       $where = ' WHERE '.$where;  * }  k" D0 s6 Q6 d
       $field = '';  
, ?% `  @* y3 a! W" |# y       if(is_string($data) && $data != '') {  
) O/ B$ \9 M, c3 }4 A: l           $field = $data;  
' q& j+ t/ Y5 S% u2 P! |# @       } elseif (is_array($data) && count($data) > 0) {    Q# i( Q$ p, E5 ]
           $fields = array();  
3 g/ m2 D1 \) X( B  c           foreach($data as $k=>$v) {  9 V4 y# t% X! ^/ S9 j
              switch (substr($v, 0, 2)) {  * v/ o$ j3 r: t% I/ f# W
                  case '+=':  " Z$ t2 U: f( [8 ^( |/ O# ~! u
                     $v = substr($v,2);  
; M; F* g( @9 P6 b2 ~0 F8 K9 m                     if (is_numeric($v)) {  
+ X. [# k& [# w- U; g                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
( k' i" e7 b# d2 x, ?                     } else {  
, \# h. P  w% ?$ p8 o, m- M$ g" }; ?                         continue;  
& U, c& O6 ?$ y% q6 R                     }  
0 S3 R7 C  v$ h* F                     break;  
* \+ n. R* h# L- G1 N- a9 T                  case '-=':    [+ N# e: Y: n: b7 n" x7 x* ^
                     $v = substr($v,2);  
* i2 B: z' R8 R/ {" L' M! T3 C                     if (is_numeric($v)) {  
. f/ l( @/ j$ m7 B                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ) |& ^8 T% Q- K- @& m; ^
                     } else {  5 [1 c0 I! K9 ?- _: J+ j1 K
                         continue;  
* A/ }6 C# V$ X: W& |) }% B                     }  * I2 C- |5 E5 F0 P/ U- A. m
                     break;  / D& @5 u1 A2 W( K, e3 d/ p
                  default:  / K+ p3 ~2 ]( X9 c
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  : v/ L8 y" G0 o" \, |! g4 K
              }  
7 N6 o# u" v$ L5 s$ V6 n* g           }  
& l" ^# X, y" Z+ ^           $field = implode(',', $fields);  ' h; a8 m/ U3 _, O, H0 y
       } else {  $ @3 @2 I; `5 Z- _; Y
           return false;  & D- P) [  x9 d
       }  6 j/ [  \! c6 Z- k* S( F0 j  x
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
& A- g% a- X* K$ a' r       print_r($sql);  
- q" y6 C+ @3 I0 @3 y       return $this->execute($sql);  5 `  Z1 u0 [6 Z& {1 v! `
    } 7 y& Q7 |1 ~. L# ^9 l
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
, t, P4 h) q8 m) V$ x
6 L! ~: ^8 y8 W' z1 g攻击测试:
) G) ~6 Q% Q$ T测试地址http://localhost
! m3 b6 m' W* _( q- L" A  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句0 h/ ]' N! e7 u+ T' a
& p4 N# o! e2 s0 P& f& ~

( s, O, N1 H% F7 j; ]3 c" d% q* c  D% O! `. K4 _  K

4 S+ b. S! J/ \' r: K9 e0 v. E; t4 o8 _

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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