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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告' Q6 j1 \1 P8 E* }
漏洞作者:skysheep' D; T* D. i& N& E
分析作者:Seay  ~& l5 {' t7 R
博客:http://www.cnseay.com/4 T: i* @/ d- f. X2 s
漏洞分析:# a' s1 g+ h& z7 Y
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
! p- J5 W6 y% V8 \: n8 p) _' h5 R" N2 u4 N* |/ `% U# X, U3 N

7 _/ ]4 X. \% i' ^1 v: b5 ~/ G
% |; J# _& r$ y' ~; _2 dpublic function account_manage_info() {  
1 @* o8 i3 o+ \" S$ `       if(isset($_POST['dosubmit'])) {  
0 T; r3 b- K4 q" a/ u& _           //更新用户昵称  
) \0 E- X: B6 @( B           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  # s* s4 a2 p* z0 s6 r# M
           if($nickname) {  & Q1 u8 ]9 i9 y, D8 |( X1 N( S
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  5 g. R' x* k+ i  H
              if(!isset($cookietime)) {  9 f% G3 i% E: [
                  $get_cookietime = param::get_cookie('cookietime');  4 @( X  d* v0 `+ o! I8 W( C2 C
              }  + B8 @: F" C6 d$ }% V
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  : Q! A" ~# F4 X8 G8 t
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  ' A5 m! D2 m/ D, O* Y
              param::set_cookie('_nickname', $nickname, $cookietime);  ' ]+ {, f1 T# W
           }  
: x8 F  c2 W$ [7 V% c           require_once CACHE_MODEL_PATH.'member_input.class.php';  
, o. \: s! \3 q4 U' R8 x  t           require_once CACHE_MODEL_PATH.'member_update.class.php';  8 D* K- A. d. Q: K1 G/ j8 ]: n& V: P
           $member_input = new member_input($this->memberinfo['modelid']);  
1 J4 ]& J" H( [/ Q, z           $modelinfo = $member_input->get($_POST['info']);  
: |, j( {8 s3 P- I# O           $this->db->set_model($this->memberinfo['modelid']);  ! g: t6 z; G5 w0 M7 n
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  + E9 K& N+ ?: s
           if(!empty($membermodelinfo)) {  
1 ?! \, X% B  c( }              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
( H( x5 G" \' X$ ~2 y% O           } else {  5 H- N+ [) I: s0 a. e1 I
              $modelinfo['userid'] = $this->memberinfo['userid'];  + J5 }! J0 T" ^4 {+ h( D
              $this->db->insert($modelinfo);  ; Y2 H# g0 d+ _2 V2 C
           }
$ n7 l! E) P7 }& X  j4 ?代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
( L; Y( V' I. K# R在\caches\caches_model\caches_data\ member_input.class.php 文件中:
7 ]0 X( i( w. ~1 \, ]+ y/ w  f2 T% j
. M7 o( C- z8 F% t% [

5 Y$ L% @  J/ G3 A1 @function get($data) {  3 M# A( W6 [. G" ]
       $this->data = $data = trim_script($data);  
# V- `% Y& f4 I/ p       $model_cache = getcache('member_model', 'commons');  
# y1 y1 T/ _1 _1 i5 G% M- b       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  : u: \( c8 Y# @& E  l
       $info = array();  
9 X3 j# }. s! N       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
0 K1 Q' _  ]# l$ E* t( F       if(is_array($data)) {  
9 j8 d0 x* g+ b           foreach($data as $field=>$value) {  / i  l: u. H7 D! r" h
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  6 a' |2 C* I; m# w+ V  z1 A
              $name = $this->fields[$field]['name'];  4 @7 W7 S& X" r. L) |
              $minlength = $this->fields[$field]['minlength'];  ( U" y$ g9 M8 Z- ~! N1 z- Z
              $maxlength = $this->fields[$field]['maxlength'];  
0 N) Y( u# O- b; \  A6 y6 x7 ]5 A* g              $pattern = $this->fields[$field]['pattern'];  
* A4 c  W& h" y0 w5 u' c1 j" S. B6 E# ~% N              $errortips = $this->fields[$field]['errortips'];  
* z' v+ q$ E. v4 y- P* B9 M, ~              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; f: E" J8 _; d" `& o) v              $length = empty($value) ? 0 : strlen($value);  
! i" z0 P. Z# f              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");    }6 G) S7 z" B- B
              if($maxlength && $length > $maxlength && !$isimport) {  
. d4 j" x5 O7 j" J7 d7 ^- i                  showmessage("$name 不得超过 $maxlength 个字符!");  / D6 t) v: n2 `* |8 ~7 w) f* s
              } else {  
" c3 ?% I% e4 {" f9 \7 f% V; K                  str_cut($value, $maxlength);  
1 n- F5 |- X4 t$ S, W              }  
) L: G! _6 E! \# h- O0 F% _0 T1 y              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
. I( N% }! k* {0 H                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ; ~3 O! p4 n5 V" T
              $func = $this->fields[$field]['formtype'];  
- Y7 i4 V4 M) e% i  T. F              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
, ]6 {, ^- A( m. r, B+ m              $info[$field] = $value;  
: v3 z+ ?4 O( g$ x7 k$ c& L0 i           }  
, v9 _$ ]% Q1 l& |7 Y  W1 f       }  4 E2 w7 ~! q! L8 D7 y3 [
       return $info;  
/ O+ S0 ?: z$ n* {( I) g. m" P6 v    } + ]) z: C- d1 W- m3 L: _
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,' E' v$ [8 ?# t# ]5 N

4 G. r6 J' Y7 o9 k* F% k4 P- b& A再到phpcms\modules\member\index.php 文件account_manage_info函数' h; w/ {) w% `& s  D) \- Y1 u0 b
过了get()函数之后。  [8 d# j3 e7 v- y4 Q& @% T
1 t' x/ S  @2 E* C2 [, S

5 J9 c7 d+ ~3 w$modelinfo = $member_input->get($_POST['info']);    }( g! y3 i% V& q4 s1 d
           $this->db->set_model($this->memberinfo['modelid']);  
9 Q7 R% \/ F% ^; |% N: @& D, L$ ~           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
- n8 ?3 U0 J: B" t/ I' ^0 t           if(!empty($membermodelinfo)) {  
4 @- |2 P+ v5 t              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  5 s* u: b8 n. |$ E* b
           } else {
# ~. W* b1 H0 R5 {* J$ N直接带入数据库,update函数我们跟进看看0 H" Q5 I5 }* L8 |5 u8 V7 x# |0 K

" h5 U: Y# z# G3 Q- g1 Q
3 F2 y4 ]9 [. g3 B6 Q9 v2 [% vpublic function update($data, $table, $where = '') {  3 l9 w# M9 W" y2 q' Q
       if($table == '' or $where == '') {  
0 k2 ?  Z( l( A' f, Y* \4 _           return false;  : Y( z/ x3 P6 D8 @
       }  " w8 n: p8 f+ w% P) M5 w
       $where = ' WHERE '.$where;  . }9 E" I3 E& E: @. ~/ f: `) w
       $field = '';  2 K; e$ g5 |9 }; |- y# ~' l
       if(is_string($data) && $data != '') {  ; d* O( s) D# }! G
           $field = $data;  
  ^, d& b. {# |       } elseif (is_array($data) && count($data) > 0) {  
- a( O" H& [5 c+ M, V+ C           $fields = array();  9 f& E$ r, s- ]  M% y! Z4 P: C
           foreach($data as $k=>$v) {  
5 h& _2 t4 `9 I: f              switch (substr($v, 0, 2)) {  ' k8 I! {' J0 @) k& `
                  case '+=':  
; l* g$ P+ ]* J                     $v = substr($v,2);  
, i7 J* G" z, b% U) W5 W                     if (is_numeric($v)) {  
$ X( H" R8 \+ M$ O* c5 B                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  3 W! r2 ^/ n' a9 @4 ?# D' ~& R4 i; h
                     } else {  7 a/ H" W* b0 y1 n: p8 N& _
                         continue;  
) E1 m! F, |7 r: S! Q                     }  1 z; H6 I+ R. b( X& p- k
                     break;  ! p* Q5 B% p  L, P' |& y; L& F0 y
                  case '-=':  6 H0 }7 }8 [+ U3 k& T( v9 t( x
                     $v = substr($v,2);  
/ Q- F, ^# c) L7 k                     if (is_numeric($v)) {  
5 k# @' ]" v5 \4 X* I                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  * p  I$ B2 Q6 J# T& u7 N8 C
                     } else {  % C- T, ]( g2 H$ j; ?( t4 Z
                         continue;  . a* p; q  n" G
                     }  
1 [& j# L3 p" H' U# T$ z                     break;  6 L- p, V) P+ g2 @, H8 _: Z
                  default:  4 c+ V. a3 _2 a7 p
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  2 x0 O. n( G4 l2 _6 p. r6 x
              }  ; m. n' f$ |& S% g
           }  * Q! C, e, U* Y3 N' v+ f
           $field = implode(',', $fields);  
& a7 b8 O1 [5 d) k. F, e+ K% o       } else {  
- v( {0 y: s4 ]2 `5 W" |! o& F           return false;  
' Y, E$ R- A' F       }  0 C7 K) \: B  ~- g
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  + f* a, v5 b* V) K* I% E" Y
       print_r($sql);  
" s6 _% D% k. [# M: ^. G9 i7 w       return $this->execute($sql);  0 Q( N4 r) U: ~
    } . H. H5 c$ O) {1 p" Y
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
: S) p6 y9 {2 U  a2 c0 ?8 f  s4 r
攻击测试:4 |0 }2 {4 a8 m6 K" v0 L
测试地址http://localhost$ o# y4 d' G7 N4 ^0 I  i8 w9 ^8 f7 U
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
" h" w7 F7 }* E+ _) T' a5 W8 w- b8 q# |) R4 j) s$ V) s

: Y; N/ {$ R( \( y0 Y# F# \6 E" K; N5 O/ o7 J3 S; s$ H

; I( b- k1 U! }2 f3 @  H' \# v
) s2 u2 j( Z& W6 t: K3 L7 S

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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