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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
7 p+ ^! g$ n" Q8 k漏洞作者:skysheep
# s, ]& `2 i6 L: j5 o% Q2 k/ O分析作者:Seay
  o5 ]9 S) y+ N; b2 e  N博客:http://www.cnseay.com/
2 Z7 |; X! \' F+ E: m" Y! `$ E漏洞分析:, ]  p4 _5 Z/ [
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。* D# f7 H, ^+ S

; k7 ]5 W4 J3 h" i/ ?: r
* @+ i+ d5 y) F0 b5 { 6 J7 W5 X1 A. P  t  C
public function account_manage_info() {  ; {) r6 o! g# K* H0 e. U  ?
       if(isset($_POST['dosubmit'])) {  1 r3 {2 |  i1 t' H% s, I
           //更新用户昵称  
; ^& a& \6 u1 a; u           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  0 A7 y8 K# d+ N: s8 q4 A# N5 g
           if($nickname) {  
# ]3 v/ C0 t: T7 {0 L( J& Z  N              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
! L1 J# r( e; c+ S- [  p              if(!isset($cookietime)) {  0 D. ?. ~' ~5 P' Y' r
                  $get_cookietime = param::get_cookie('cookietime');  1 N1 v0 w3 w! D2 k8 o6 H
              }  . n* J/ ^  W5 N" y8 K2 f
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
, J3 D4 S4 ]' z3 i8 q              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
: C; v' x* m' s+ P* b1 B              param::set_cookie('_nickname', $nickname, $cookietime);  4 V, Y$ I( C) t7 {, D
           }  % Z1 f% W+ i% p3 W
           require_once CACHE_MODEL_PATH.'member_input.class.php';  ) q3 V( C- T1 r
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
, y2 d+ o2 f9 p5 D; i           $member_input = new member_input($this->memberinfo['modelid']);  0 o; a( n1 O" Y3 R* H. L
           $modelinfo = $member_input->get($_POST['info']);  4 J5 t! o  W  b- \( D  {$ c  e
           $this->db->set_model($this->memberinfo['modelid']);  
; j3 l$ q: B4 O5 K; ?! [           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  0 s. s# h+ R5 \5 S3 x
           if(!empty($membermodelinfo)) {  - ]6 ]! o8 m  `8 D
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  0 m( L; R/ E* ]6 x5 G* d
           } else {  ; f# P/ O( }! f$ _  E  y
              $modelinfo['userid'] = $this->memberinfo['userid'];  . i9 F& Y+ e' k
              $this->db->insert($modelinfo);  : D7 H2 ^2 x/ I& U
           } ) j% O8 X: e( A% T+ @* V, E
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
1 V. |/ m3 O9 @在\caches\caches_model\caches_data\ member_input.class.php 文件中:
* V% R" ]- L; j  R. w# ~3 @, v( Z
. x; r) P. R' |5 H2 k

. A" z4 C+ ]4 t/ Z1 vfunction get($data) {  
9 M5 ~# d+ V1 K) R: S! c/ j; w, h       $this->data = $data = trim_script($data);  2 n6 q6 g* ]5 }* t; C
       $model_cache = getcache('member_model', 'commons');  7 R  k, R& b7 k
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  7 p* a8 c3 U- W& i
       $info = array();  / p" \- w+ A  A. S  M/ H
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  9 C6 k$ y9 U& g; ^* {4 o* }- _* F: N
       if(is_array($data)) {  
) `+ y" y  ^4 ~% W; y' q           foreach($data as $field=>$value) {  8 i& d! B* w9 a1 s# \% ]# m7 a
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
- I) O+ c. t- L0 @              $name = $this->fields[$field]['name'];  
3 ^/ j8 q! b7 \2 ?. @. X! l9 T              $minlength = $this->fields[$field]['minlength'];  
$ i. k+ `1 T; r! s7 K* W              $maxlength = $this->fields[$field]['maxlength'];  
0 t8 C. ]: ?+ K% x- a1 v& j# h5 u; ?4 B6 c              $pattern = $this->fields[$field]['pattern'];  # `% z& _) v2 |/ b9 r4 x* N. w
              $errortips = $this->fields[$field]['errortips'];  
. D9 i9 E; C9 f6 J1 ]; o' F- e/ r              if(empty($errortips)) $errortips = "$name 不符合要求!";  / V( k9 L8 ?9 {# L5 W
              $length = empty($value) ? 0 : strlen($value);  9 P) B- J8 ]/ X7 a3 z" J
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
% ~7 d3 h& c( ?              if($maxlength && $length > $maxlength && !$isimport) {  4 ]. y! R1 v- D
                  showmessage("$name 不得超过 $maxlength 个字符!");  
1 s- k7 g6 @' f; X+ B6 u) f              } else {  0 z' d+ S! E, |
                  str_cut($value, $maxlength);  + K2 F3 b; l- f' Y, c  p
              }  ' O- J! u; q; m
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
! r& o5 s1 w. |  @4 d/ R                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  8 O% D8 J( T( a6 P/ O. x0 ^2 l# v
              $func = $this->fields[$field]['formtype'];  5 X. H, D1 U7 E4 i/ F4 n
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  1 e& @" n1 N, d
              $info[$field] = $value;  
- j3 Z/ W! d& C           }  8 j& E0 ]0 N1 J+ f  N2 u7 |8 x  E
       }  9 b3 {5 K5 J' ]( f7 k
       return $info;    e* ?2 y6 X  [/ |% t
    }
9 ^( R4 p# i$ ]: Z) x4 Z) ?$ ?/ Ltrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,9 A4 J9 `' ]+ M7 G, n( @. ]
$ x" f! H% T1 v! L: z; ]
再到phpcms\modules\member\index.php 文件account_manage_info函数
$ k. ?) m5 \. j9 i; S9 S* ^过了get()函数之后。
/ }. f( [9 g1 o' L; V0 C: {+ S' d$ \4 j
! M/ u, B0 W0 J
$modelinfo = $member_input->get($_POST['info']);  6 I: h' O5 e2 G* v9 R8 J* q2 d' m
           $this->db->set_model($this->memberinfo['modelid']);  
5 y9 M4 x5 A. j7 y2 R           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  - C2 e# k1 S8 \9 O
           if(!empty($membermodelinfo)) {  
- u  t# M$ X' \9 t+ r              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; k& a, N$ n1 U7 `% h$ W
           } else {
* L( X1 P( A8 Z# R6 l直接带入数据库,update函数我们跟进看看
" }; J& [: x6 u* ]# n- H2 d% H
# J& \1 |6 G3 z( c+ t- \2 m
! i6 L: L9 `* J. k+ l1 o* T, qpublic function update($data, $table, $where = '') {  6 A7 F+ a4 ?+ k% r. P. T
       if($table == '' or $where == '') {  
/ Z# \! m6 n/ e; c           return false;  ! M$ W# ?+ l* e- I/ }& |
       }  ( H6 z6 V8 ]$ q' }
       $where = ' WHERE '.$where;  
7 K4 o. A* H4 ^( A9 C       $field = '';  9 z; N( W6 O8 B/ I# X4 o; f: M" y
       if(is_string($data) && $data != '') {  7 o4 o4 L5 e* F! }
           $field = $data;  - u6 y$ _( _; `: K+ X6 e, A9 C
       } elseif (is_array($data) && count($data) > 0) {  
6 m) W) g5 Q) t: o0 U# L" W           $fields = array();  9 m) N: P* `8 x* ?2 V8 t3 z
           foreach($data as $k=>$v) {  
+ O9 U; L( U) a              switch (substr($v, 0, 2)) {  
( Y+ c1 r, b  h8 L) \; s  w                  case '+=':  
- a" V. d7 w8 E9 Q: ?( t                     $v = substr($v,2);  
6 q, I! E6 }, S                     if (is_numeric($v)) {    G/ q) k" t& P/ Y
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  : U+ m6 b3 _  u2 V& a6 q9 z
                     } else {  
7 t3 S8 ]' e' r' \3 D6 {0 z$ l                         continue;  
: P% U5 s. S0 _3 Y" W                     }  
) ]0 P7 G( `+ ?, {                     break;  " x0 F; x! E& A5 M# b
                  case '-=':  
0 G- N' h# `# c* q/ i& r; m                     $v = substr($v,2);  " B) a# a, L2 M6 S
                     if (is_numeric($v)) {  
" |# i( b3 Q) j7 N+ p, l. L5 `/ W                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  , d$ X2 C" n9 {& Z& R  n4 g+ E
                     } else {  
$ A) d6 z# w4 e1 D                         continue;  
$ v$ `, T4 a/ V; w8 c# |$ R                     }  
  a$ O7 ?% @8 P; a2 |! o3 F: n3 q                     break;  6 |& ~: B& N2 B( F9 N7 C8 P, B
                  default:  ( ^+ G% {& _8 ]6 w/ x
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  7 {3 A4 M! u+ X. s! J1 a0 S
              }  
6 Y( w: Z/ _0 Y* \9 f2 `2 }; c           }  / T8 v$ \2 V3 N" l# B
           $field = implode(',', $fields);  / ]9 g/ s9 i+ _- X0 U0 o5 g- D% I
       } else {  + p( V2 F7 M* F& ^9 c) }
           return false;  
$ }. d1 A2 ]* r: P5 H9 r       }  
, T# ~% L3 X; x# y: B       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
: F$ G; S3 r' k       print_r($sql);  
4 q5 F3 G  v, b. p7 P       return $this->execute($sql);  
# d+ P$ [& u! y    } ; [4 ~/ F& x- C- E
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
0 A9 |' j* T, c/ z1 [: t( a& x( X+ [" |/ [7 u0 I  d) S& ?
攻击测试:
; R" l6 E! _, l测试地址http://localhost. X, ]0 [! Y/ \# k9 a) s
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
+ @: p, t9 R# F: n* F, M
( ?9 V8 t  M, D. e& ?. I 4 b& G/ ~4 E8 d

3 v/ A3 W4 d5 b: r+ D% _: A
% X, z' ^) l2 v" h
2 }9 s- ?& C& L! `3 z1 }1 c. \

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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