找回密码
 立即注册
查看: 2917|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告& _( T/ M: a) @: J: M1 v; v
漏洞作者:skysheep+ B4 B8 p( j+ Y9 L" O% C; S; i
分析作者:Seay
/ S. S$ `  ~0 k' j1 y博客:http://www.cnseay.com/
3 x1 ]& ]0 i' n1 t( P7 ~. ]漏洞分析:9 m- y0 Q7 ~; @8 r. V, z
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。5 v8 z- N3 X# W3 _7 n, c
  B; }8 f; k5 ^! \/ ~
  C( I& |- s5 R0 B! w6 X

5 e0 q" I  i3 e) L/ Upublic function account_manage_info() {  ' B% f. x$ t1 D; p7 t. L1 o8 `, l
       if(isset($_POST['dosubmit'])) {  . |  S" ]0 `3 I. C
           //更新用户昵称  
5 i: @; c" z% u  S& p/ s           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
8 L: M$ p; W$ i           if($nickname) {  6 k9 Q3 [# s9 m: C. O3 M2 D
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ( _' R* C! X) x7 T. E4 L: }
              if(!isset($cookietime)) {  ) j; m3 r6 J6 N5 r
                  $get_cookietime = param::get_cookie('cookietime');  7 p' u6 F- i. j6 n, G3 d+ [9 @. p: j
              }  / p1 y2 l4 Y+ V4 E* C# m( q2 D/ l
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
" r4 R! v% a$ L9 W# X$ A/ X% u4 W, C$ v              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
9 ~0 A+ h- ^# U, f5 ]              param::set_cookie('_nickname', $nickname, $cookietime);  
9 N- m6 e9 W: o8 T           }  
) Q7 W$ Y/ u2 s% D! p( ?           require_once CACHE_MODEL_PATH.'member_input.class.php';  
- H/ q! N  o0 G           require_once CACHE_MODEL_PATH.'member_update.class.php';  $ B- j+ M, z0 k7 g
           $member_input = new member_input($this->memberinfo['modelid']);  ( h0 G- j5 d! @4 v$ l' H4 v
           $modelinfo = $member_input->get($_POST['info']);  
1 d! O# k9 `. f2 s6 z           $this->db->set_model($this->memberinfo['modelid']);  
' G3 D' q/ h4 |           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
8 @$ S- L' M1 c- P0 H4 V& ]           if(!empty($membermodelinfo)) {  ) m' m% d) L+ ~* I# y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; a7 |, o5 K0 ]) O+ b
           } else {  
# H0 @( w2 O& k% ^0 G2 |) Y              $modelinfo['userid'] = $this->memberinfo['userid'];  
) |) m2 ?5 H2 s4 d% n4 O              $this->db->insert($modelinfo);  0 v" m, T+ E) h) b/ j; n- C
           } / K! T; [( r% G" @2 G' y
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,! C1 E% W* D) m6 A7 y9 f# E6 Y) |
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
. L8 [8 A' n* |2 |  @: g0 m# R7 g+ p! `$ W; B3 X$ h# o0 E

. I) ]: E# t* P0 M, t+ V5 H
2 o9 D8 \4 R. q+ f9 p! _function get($data) {  
/ \8 p$ v- o% P8 m, O       $this->data = $data = trim_script($data);  0 V/ {# e7 [4 H8 a# s
       $model_cache = getcache('member_model', 'commons');  , C4 C, D: ^2 k! \! i) h1 U
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  , E% b4 ~$ Z$ Z' N
       $info = array();  . ?' A$ T4 Q4 P; }& h. B' ^3 J
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
% \8 \: o: p9 d; C       if(is_array($data)) {    _. ]9 Y7 N6 Q# j. ^2 T# m' r
           foreach($data as $field=>$value) {    e7 {( B+ X& h! e4 i* |) S
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
" {" n, U3 @0 T; Y" J: N              $name = $this->fields[$field]['name'];  5 C$ i: d/ D, r
              $minlength = $this->fields[$field]['minlength'];  # w$ ?& J4 d- [* S
              $maxlength = $this->fields[$field]['maxlength'];  
% R7 R0 G9 F8 Y1 K7 j1 ]: k, X/ E              $pattern = $this->fields[$field]['pattern'];  
" h: {8 j! _# r, m+ q              $errortips = $this->fields[$field]['errortips'];  ) M* X$ s4 T4 E. h4 J
              if(empty($errortips)) $errortips = "$name 不符合要求!";  % \6 `: W7 M, n8 o! o8 m+ e
              $length = empty($value) ? 0 : strlen($value);  - H, {! u) ]5 e( G" g4 I3 b% ?
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ; o0 F$ d6 X- J* ^% q* l# n, ]
              if($maxlength && $length > $maxlength && !$isimport) {  ' y5 g9 R5 w- I6 T# p+ ]6 G% O
                  showmessage("$name 不得超过 $maxlength 个字符!");  6 h6 r: \1 I8 w. ^
              } else {  / _, t; L# ^& i: K' ^( ]
                  str_cut($value, $maxlength);  
! s4 U  j* R) k2 [. G              }  
; x2 z) X/ }& L! _8 g              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  / b5 I: ~! P& _& h5 |+ t
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  6 P9 s. m. U; A7 U7 j
              $func = $this->fields[$field]['formtype'];  4 q/ ?! a) \- s, U/ `
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
5 d( Q" B5 q0 D1 H              $info[$field] = $value;  0 o0 P+ F. Z9 f
           }  ; K5 Q2 v! _1 j
       }  
' l0 }* b- d8 l: i/ Y# E       return $info;  * X0 g* t( `9 Z+ S
    } 6 Z" p7 m* a+ x6 M( K" _, i
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
) A- p0 Q3 ^; ?8 H7 K9 N
; m- U/ ~! B; |9 k1 F& \, n& @再到phpcms\modules\member\index.php 文件account_manage_info函数
/ [. ]( i9 w9 Y过了get()函数之后。6 [2 o8 _. E3 a1 t

' k8 r* q' \: z( _ ' q8 k5 N: O9 z4 G5 b, t* C8 R
$modelinfo = $member_input->get($_POST['info']);  $ V: w2 ^1 L# ^" C1 P  \9 g
           $this->db->set_model($this->memberinfo['modelid']);  
% }1 W: i( w9 J# e5 O           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
0 `7 l5 z5 \- B           if(!empty($membermodelinfo)) {  
; L6 \3 b+ P' ]4 f% `              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  0 Q2 ?! g( U) E" u/ ^, V( K2 k
           } else { - ^; Z7 K1 l* m3 |: E) R% P
直接带入数据库,update函数我们跟进看看
" H  t6 }( J9 \2 ^6 B6 ?3 X: i
  a; z/ ^- }) z3 b% C- ^
/ m# O- w" H' Q) L1 v  t0 u1 o( tpublic function update($data, $table, $where = '') {  ) o2 F9 Q) @- X2 D; m0 p6 @
       if($table == '' or $where == '') {  
7 P# P2 s4 C/ P$ m           return false;  ' a' C9 S2 o! B! d" e3 s8 |
       }  
  ^% o& d+ n) \* I       $where = ' WHERE '.$where;  
0 _, n0 f0 H! e; a7 |3 w# f       $field = '';  ; T8 Q, l# ~9 M1 F/ Y' x
       if(is_string($data) && $data != '') {  ! n4 M. ^9 U  f5 L% q$ Z
           $field = $data;  
: o3 H" ^( j9 N* _, m( M       } elseif (is_array($data) && count($data) > 0) {  
) V# ]! D$ }) p, P, p% H           $fields = array();  
+ B! H5 S) Y  e; p# u  l+ V2 }           foreach($data as $k=>$v) {  
: {# I: b5 o) S7 |' S$ R) x              switch (substr($v, 0, 2)) {  3 l7 j8 m5 |6 U% \; H, R- S. N' {
                  case '+=':  " I4 u) R; {6 ?* n
                     $v = substr($v,2);  
' ?3 i" k6 i. |% F3 \                     if (is_numeric($v)) {  & `' M. d) P# g, R
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  % m5 Q8 S6 \, V( Q, |  T5 F& l
                     } else {  
$ x) `6 C) d2 F: H8 ?1 |" G* ^                         continue;  3 F% ?, {  y# Q4 c5 h8 [  C
                     }  
, S' I$ j3 l7 ]" l- @% s                     break;  
' C, w* s8 h+ M                  case '-=':  ' C) [+ `! |: u/ I
                     $v = substr($v,2);  ! V0 c. {4 r" ^9 |1 M
                     if (is_numeric($v)) {  
  W% a8 x. j, r                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  : S3 u7 R# ]' h' N: {( u
                     } else {  ! O  i. n/ g% E0 _3 i
                         continue;  / I' d* L) g& K& h1 X
                     }  5 Z  @( i4 H2 B" @2 r: i- H* y
                     break;  # _! `) Y+ Y* E9 V, B( ?# h
                  default:  
6 |% m) d- J6 x% W# h4 ^                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  , `  Z' c* b- c
              }  
' I. }4 \' V8 X7 g+ b+ J, u           }  
% b1 m! P8 [" O, B6 U' L           $field = implode(',', $fields);  0 T3 G: A" t+ }; P+ C0 F
       } else {  , d9 @& n1 h9 V
           return false;  
: h' c( w& B4 v7 P3 Q       }  + T3 u5 \" a* x
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  / E( h% v  |7 v
       print_r($sql);  
# Q4 [7 m2 k2 l% ^& }2 h3 i       return $this->execute($sql);  ( r# [$ V' |8 g; g  j
    } 7 }  ?& j% n$ Z" ?, l
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。& L1 U9 e+ [$ k/ p
4 M: i6 m& s; h# W* h( k
攻击测试:
( I5 }: {, j7 |6 k) W测试地址http://localhost
2 h# z  e; Z3 n7 D. b  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
& j! Q3 K5 L/ A( h' _- v9 B5 r0 }5 ]4 F0 m7 m
. }  b( U( a% X
# S  f/ h, C; ]0 P9 c3 C4 \! b/ I
) ^5 v" _& {/ i1 L
) B( N2 I# [4 h7 G* L' p

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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