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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
: D* ^' n7 C# X" z漏洞作者:skysheep9 Q/ l5 ?; H5 t- A
分析作者:Seay2 R' q& p9 l4 n& n
博客:http://www.cnseay.com/! n. k8 k' l/ S
漏洞分析:& H+ B8 F- l3 [& M3 m' w
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。; a4 R7 H! Y5 u6 T6 N0 c$ U+ N! w) J
; G, \* n0 n8 g0 C( }
+ {" \  e4 g( z7 D0 _
! t( \: r' e0 s# b% L$ L
public function account_manage_info() {  
: r9 m. l4 M2 d, A) @: R       if(isset($_POST['dosubmit'])) {  : a1 m7 ^9 a. F- P' @& u4 e
           //更新用户昵称  
/ q$ B: y( i! l$ h: b$ n- E! y# b& s0 i           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ) `0 E8 B. e& }7 b+ F" A
           if($nickname) {  & S/ A2 u9 R- D& j; @/ e3 d- K
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  3 T5 ^/ `3 \; p% ~5 z8 _) u
              if(!isset($cookietime)) {  
7 d, ^7 J  X2 O: v: \                  $get_cookietime = param::get_cookie('cookietime');  1 R7 U  M8 e& ^8 X+ N. n4 N% ?8 n4 ?5 s
              }  ; T2 p1 \' B2 G! v5 o  Q
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
8 N3 \8 R- U  @3 |              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
- M# h4 M+ s1 j- ?) p/ y              param::set_cookie('_nickname', $nickname, $cookietime);  
. a8 Y) F6 G6 T% c           }  
# q3 ~9 I' h, X% j           require_once CACHE_MODEL_PATH.'member_input.class.php';    n/ o5 f1 V7 N" P
           require_once CACHE_MODEL_PATH.'member_update.class.php';    Q- u+ E6 w, B9 ^: h# O0 p
           $member_input = new member_input($this->memberinfo['modelid']);  
- Z* A5 L" f* e; z2 S           $modelinfo = $member_input->get($_POST['info']);  & I) d# W5 U  T+ }' r
           $this->db->set_model($this->memberinfo['modelid']);  9 o# ~! j/ ?* [* n- D
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  2 I+ k5 s; p$ o0 `! O: b! B; |. j
           if(!empty($membermodelinfo)) {  
8 ?: x8 H& g$ J              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  " I# n* X. [/ O7 ]' K
           } else {  
- ]0 W9 x/ e: [0 `/ ]              $modelinfo['userid'] = $this->memberinfo['userid'];  ( ^! E+ @( W  E9 L" I6 O
              $this->db->insert($modelinfo);  
+ e' O+ r( }0 r, A$ _0 O           } 0 N' u- ?  Q+ u; y8 Z
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
) y" i8 G6 u5 D在\caches\caches_model\caches_data\ member_input.class.php 文件中:
# q  f* b  P( r6 O
7 r  `8 l" @5 v5 D3 D
5 T2 e- s: ~7 _1 g
6 h6 d' D- l( _$ vfunction get($data) {  . `7 z1 k* U: _' H/ `8 P) p
       $this->data = $data = trim_script($data);  
) g7 r# ?/ A5 k       $model_cache = getcache('member_model', 'commons');  
" v1 r, i. ?2 g( I, F/ i       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  . Q8 N8 A& @8 M  T4 }8 g- n' y
       $info = array();  
4 J& `# U6 B% |8 n5 Q( {       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ( T3 _+ l& W2 z6 k. K7 |% |8 h6 A2 H
       if(is_array($data)) {  
( W. C2 u5 \( ^4 T/ {/ l  B$ P' I           foreach($data as $field=>$value) {  
/ `5 O, w$ Q* P/ ?              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  7 F. j4 r+ q" c. Y! D; H# R' j
              $name = $this->fields[$field]['name'];  2 J% |4 \2 u' Z. Q8 C4 `4 C: h
              $minlength = $this->fields[$field]['minlength'];  
+ A( N" M2 {( ~$ w* I) _, F              $maxlength = $this->fields[$field]['maxlength'];  
9 Y4 G1 m/ ]" F0 M) B              $pattern = $this->fields[$field]['pattern'];  
) V* k' i; Z1 k3 k0 S              $errortips = $this->fields[$field]['errortips'];  
( K: h0 C1 o3 @3 Z5 M- K# Q* i              if(empty($errortips)) $errortips = "$name 不符合要求!";  
) [: ~; X6 b2 S$ W( F2 r& C1 x              $length = empty($value) ? 0 : strlen($value);  
! z5 ~$ t; V. l% C2 m              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
. Z3 v0 x4 ]1 u- q( o2 V( ^) ^              if($maxlength && $length > $maxlength && !$isimport) {  
( N2 ]  L/ G5 ]. X4 I/ H                  showmessage("$name 不得超过 $maxlength 个字符!");  : `! g% w$ z* J6 E) [  d3 i% s
              } else {  
3 L8 o4 ~+ U* j4 @& M- J                  str_cut($value, $maxlength);  9 x) }7 o' m5 g1 ]
              }  3 D- [3 ^& y9 H3 q
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
  P) }6 c. `! a9 u( i                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
1 X! L) Q8 k3 S; W! x. U              $func = $this->fields[$field]['formtype'];  
) d, {! u0 H( u0 m- F+ I, Y              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ( G7 I+ b5 T- G% o9 w5 K# l0 }9 s
              $info[$field] = $value;  
/ B1 r) i( ?) m# s3 @' s           }  2 G+ ?* k$ d$ u3 Q' r
       }  3 R6 B1 T: a1 V7 J& ]4 u
       return $info;  
. K' g: ~$ n8 X1 s/ A! V    }
* M/ y1 H# X; {# U- qtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
3 U- ~  O# a$ _1 t! Y8 k
0 B7 _$ }9 o: `) {) R再到phpcms\modules\member\index.php 文件account_manage_info函数
3 Y* }+ Z- E4 S2 |+ M% @8 K" M8 }, v过了get()函数之后。
  m: e( U- k2 c3 K9 e9 Q/ F9 O( F
$ I6 ]4 Q4 y* H& X- M2 f
5 ?; w1 K$ c% ~$modelinfo = $member_input->get($_POST['info']);  + l1 W- N2 e% z, O- F
           $this->db->set_model($this->memberinfo['modelid']);  
* f, w8 F. ~- s           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  : W. s! x' I3 ]! J" i2 z+ u
           if(!empty($membermodelinfo)) {  9 F- `% Q$ d; E
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
! e0 ^: ^# R+ p; i1 a# i5 |           } else {
9 z( Z) {. c# ?* l1 h直接带入数据库,update函数我们跟进看看
, p8 I; q/ l7 r' Z  R0 B  W) k2 V5 t9 c; `
0 K. f8 _& ]0 n- c$ l3 `
public function update($data, $table, $where = '') {  
& M% s0 t! R, j* p# _0 g' l       if($table == '' or $where == '') {  ' N6 W3 y3 o. H
           return false;  * B1 k9 Y/ |1 \9 W0 M
       }  
: v- k  A8 @: ~0 l9 n: e       $where = ' WHERE '.$where;  
3 s. y5 e% N0 ^       $field = '';  ; u1 X( u4 |$ e4 U5 N, f
       if(is_string($data) && $data != '') {  
" y; ^- x3 K% g, @1 V- j5 N8 u: u           $field = $data;  
$ C! W2 s1 ^+ r* O* S: a% |       } elseif (is_array($data) && count($data) > 0) {  3 E* E) H* q. H) @  e
           $fields = array();  
; d7 n" O' _# r# _" ~5 X+ z! R5 h           foreach($data as $k=>$v) {  5 M& l2 x+ O3 b" o
              switch (substr($v, 0, 2)) {  
4 E  h" O5 D/ k8 d$ R& ]; p8 t                  case '+=':  
' v/ L7 L+ t8 ?0 J1 H% T                     $v = substr($v,2);  ) X3 {' r' G* w. U
                     if (is_numeric($v)) {  % y0 q7 S1 w1 N9 x
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  4 D4 D, J# V% V/ |& e/ e
                     } else {  
3 p: r2 z" m5 v% G                         continue;  
8 e) B: J# [) j- X3 b6 c                     }  ! J0 f2 U( g1 \0 g" K$ ]
                     break;  ( k1 z" R3 \& \5 R! Q; X7 \
                  case '-=':  
! m" I/ H: y8 D# A& f                     $v = substr($v,2);  
! {- Y1 K  ?; T/ [                     if (is_numeric($v)) {  
/ h8 B) @* K" d( A. {% V                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  + p, |8 p8 s5 ^) }5 |2 d1 y
                     } else {  - j2 K* X% Y( I; E2 r' {
                         continue;  # J" j/ w9 m8 x7 y
                     }  
# G* D5 w' b1 Y                     break;  2 `# Z5 E* i0 B
                  default:  ; l& ^: ]' n+ o5 i9 A6 l
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
- b/ _5 x- |+ x2 s0 E) a              }  ! U; d+ L3 ?0 d- a; T! S; q- E
           }  3 G/ Y/ k; w/ Q6 h! I
           $field = implode(',', $fields);  ! z' T+ b' g' a/ ?9 `: A- q3 a
       } else {  
: V# a6 Z6 G0 h% t" C+ G           return false;  
1 \2 s' [; h8 [* a       }  
3 _1 G4 K4 Y; Y2 d       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  5 l6 r5 p3 l* a+ j" n6 U
       print_r($sql);  
7 a( y) {( U5 z* I* v       return $this->execute($sql);  & s5 ?& T5 w% C' C3 Y
    } 3 F$ \+ ^! v9 b2 ^% ]3 ~  C+ x- U
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。9 w8 l; Q7 D+ A/ a) H- w9 m

4 i2 p. @( }2 n) o, b攻击测试:% s5 X  K7 X# ^! i5 ?  t+ J
测试地址http://localhost* c' U* k: \& U9 o  I1 v* U
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句- X- G4 K' N6 i! s) T2 |8 F' x! d

  X, |% M, g5 y: [2 j2 {- |# g' s6 Y
# o, K& F) [  [4 }- y/ l
! x% G4 A$ N/ i. S" Y$ f+ M' Q5 e/ R; `: a: t
7 t. l" N7 k% O" D0 R$ Z+ C

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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