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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
/ F! t, H6 L- j( i0 b+ c漏洞作者:skysheep
  w8 s, |  @; H3 p& l0 C5 z$ h0 K分析作者:Seay
: M' V% a& S1 d& W' o: o博客:http://www.cnseay.com/, O% P% U  d; _8 ?& e# f
漏洞分析:' T$ y6 @* x. ]+ K5 T8 i8 g
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
  g- T: {5 D0 _
% Q# N, l& l9 H9 U' }( T- j/ v! Q: U7 v) \

* g: S4 r3 O- a) j3 V" ~- dpublic function account_manage_info() {  1 V+ Z. _. c" h( y% p* ]
       if(isset($_POST['dosubmit'])) {  
, f# U2 A$ y( L% _3 \" w2 w           //更新用户昵称  ' e. f9 ~* d, j1 ~+ R* ^1 Z
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ) d2 e& J: q* F* I, l" v  i5 H; e
           if($nickname) {  ) h' l* ^% y& g! x
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  + u, Z# R5 F5 T4 v* @+ g
              if(!isset($cookietime)) {  
; S+ e4 C- Y* j                  $get_cookietime = param::get_cookie('cookietime');  
& P# M9 r2 a- A3 Z# P* u              }  $ O/ Z: [, C. ]. _
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
6 t; I) L/ [' U1 V7 l" X, s  V              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
6 n, D# b# e# \( A              param::set_cookie('_nickname', $nickname, $cookietime);  
2 M$ S. \  P3 N" G2 c; a0 Q           }  ) K: w& H2 M9 h# q3 _
           require_once CACHE_MODEL_PATH.'member_input.class.php';  * j' t1 U$ `& l  x
           require_once CACHE_MODEL_PATH.'member_update.class.php';  1 L8 Y" l( S2 i! I) ~
           $member_input = new member_input($this->memberinfo['modelid']);  6 g  g# h8 c1 n8 ], {
           $modelinfo = $member_input->get($_POST['info']);  ! Z  }. B% ^% R1 R9 d) d/ `
           $this->db->set_model($this->memberinfo['modelid']);  
3 m, \5 t1 M+ E6 p" L           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  5 f0 o) I" R% \( z
           if(!empty($membermodelinfo)) {  6 c! [8 f  B1 |4 U' T6 \) e! ^
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
- i1 N% _& l: ^           } else {  * p# z5 I2 j6 m1 p7 z  X
              $modelinfo['userid'] = $this->memberinfo['userid'];  
# b. m( |& z! D! P              $this->db->insert($modelinfo);  6 ?( u+ j. E3 ~
           }
  K$ k! u  H+ w% y代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,/ \: E) ?/ h6 h/ e9 M0 Y+ ]$ {$ M
在\caches\caches_model\caches_data\ member_input.class.php 文件中:4 S& y8 A* c! b7 g: Y% u

3 S! r" I- c' b  X2 Y8 _0 o
/ z7 k/ O8 F+ Y
0 a* m2 M* h' e$ G6 ]function get($data) {  : b/ |3 N+ }/ I
       $this->data = $data = trim_script($data);  
* S% T; z% x, g8 H4 ^7 P       $model_cache = getcache('member_model', 'commons');  
5 A' V$ x% s0 R3 c) x& c       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  8 }0 v$ g- v! p; ]: Q
       $info = array();  7 y9 ]& }, r5 {0 m
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  : c8 P6 m) d- M6 Q
       if(is_array($data)) {  * `; u# ~$ C7 \5 |7 o8 r3 y' J4 I
           foreach($data as $field=>$value) {  9 W+ K7 }- X7 A, x  |4 S7 N
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
1 I3 l, I1 G: o  x. ~+ v- a- k9 l              $name = $this->fields[$field]['name'];  ! ]; r7 n/ Y+ ~: b: Q5 a
              $minlength = $this->fields[$field]['minlength'];  : P" L& w% s+ h
              $maxlength = $this->fields[$field]['maxlength'];  7 S8 k9 k# n0 j1 v9 [& M
              $pattern = $this->fields[$field]['pattern'];  
( q6 {% F0 i: t- n              $errortips = $this->fields[$field]['errortips'];  ; A. d1 K$ J1 `) {' `: j
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
) s0 }. j' T& I1 K& e              $length = empty($value) ? 0 : strlen($value);  
8 X+ W! q6 B$ _- H, v% f8 C& |/ g              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
# i% |/ [- z! C6 T$ o+ e6 u              if($maxlength && $length > $maxlength && !$isimport) {  - F! b% _+ b2 O2 V$ @
                  showmessage("$name 不得超过 $maxlength 个字符!");  ' o3 H. K) o0 j! w6 q( T5 J7 u
              } else {  ! O, V- m( W4 \
                  str_cut($value, $maxlength);  
( r% a0 M. ]5 L) D6 B              }  
9 `! e5 k  z  a: \              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  # N& G# j' `- u) r' h
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
6 Z9 o! f6 ^8 ]% w, N/ ]) e              $func = $this->fields[$field]['formtype'];  
3 O& O$ g2 H. w8 C/ d* _              if(method_exists($this, $func)) $value = $this->$func($field, $value);  . @! N3 l: p6 z
              $info[$field] = $value;  # ~8 Z6 [6 \; q/ a& _# y
           }  2 r: ~- ]' o( i8 }4 S5 p
       }  * W% f: P- T  {+ ?; a6 f
       return $info;  # X8 R& c+ s! I* A1 G
    }
) @- L$ x: I0 \2 Atrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
, n! F# y6 k+ N, \9 j
/ J  f, |5 O3 m6 W* D6 N2 i再到phpcms\modules\member\index.php 文件account_manage_info函数5 D! L# `. o0 `: p' J+ i6 ]2 @
过了get()函数之后。, h0 Y6 b" D$ D
; B; M' `% b3 N! U: Y+ a, t

; G! h" P- M" b" U7 `6 ]( P' K; y$modelinfo = $member_input->get($_POST['info']);  ; E& Q. z3 K6 Q$ E4 Q9 o) w# f
           $this->db->set_model($this->memberinfo['modelid']);  
- V( o( A: a7 G: C           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  7 K8 v# ~5 }) g+ l: q& Z! r
           if(!empty($membermodelinfo)) {    T0 U( f$ v; T' ]
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  9 L: V; i2 D. q* Q2 L. ]' m* i& H
           } else {
: y5 Y% Q$ l1 f5 e$ Q1 r% Q! A直接带入数据库,update函数我们跟进看看/ W/ E$ Z( R7 T, s/ {

5 r& C8 e1 M- U & `: Y  N7 @8 l  w
public function update($data, $table, $where = '') {  
3 e: O2 T, x& j8 K; n       if($table == '' or $where == '') {  
+ d4 \7 \: p4 x           return false;  
  T2 D6 F& k# ?$ n5 E4 q, K) X       }  
9 e& ~& k1 B% W- N( P+ M& T       $where = ' WHERE '.$where;  - ]& ~* l, d& i: U
       $field = '';  
1 I0 q' a* n8 W       if(is_string($data) && $data != '') {  ! T: L$ ~+ r& U, C. b
           $field = $data;  # E2 ?1 x- r) C7 W& w! f
       } elseif (is_array($data) && count($data) > 0) {    z, r5 P, G" f/ A. u
           $fields = array();  
8 z3 t5 K6 r$ s- i1 w3 Y  C           foreach($data as $k=>$v) {  , N0 E" V" Z3 q, v/ p
              switch (substr($v, 0, 2)) {  
1 Q/ s/ D2 U7 E; i2 d. O                  case '+=':  
5 E6 u4 h: w9 l+ a                     $v = substr($v,2);  
" E+ w, |+ I8 y7 }" j2 [" ?3 K" O                     if (is_numeric($v)) {  
2 }$ c' @) g6 D& C, n                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  " ~. J  R0 x) z1 G* W. c
                     } else {  % s) G/ w6 U& j1 V# L; R
                         continue;  7 ^0 p" g6 n9 Y1 f8 u, a
                     }  ' x+ O: a1 k# Z& c4 R
                     break;  
9 r5 t8 X" n( S; [" b0 L! c                  case '-=':  
( u* h. S1 L1 {0 t                     $v = substr($v,2);  * F$ l, ^4 F3 E
                     if (is_numeric($v)) {  
# o5 `2 j: u/ G' n/ Y5 Y1 ?                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  9 o8 m5 }2 @$ J3 K9 v4 L( _
                     } else {  3 z( v2 Y  x1 M$ @% v; x( w
                         continue;  
" A" o0 {8 G& I( ~. x8 M                     }    p+ p0 g' _! X& o3 B
                     break;  + U. S: Z  [* c0 K
                  default:  ( m( l) |% X: M5 Z4 p0 g
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
6 J- q1 `1 u2 l# k5 o$ r% @              }  . v6 c! _8 P) d$ e6 _, [+ W" c% {# C4 T
           }  
7 |/ `" ^  {$ z7 _/ D           $field = implode(',', $fields);  $ n; q! |# ^1 x* b( d- Q$ {
       } else {  % A) O' ], O/ N, ^4 U' ^- b9 w
           return false;  ; I, T' H. M" n
       }  
- `6 g' w4 R2 s* I* W0 ?: S/ x       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  1 r0 g$ S0 Y7 k2 a" t
       print_r($sql);  
9 g8 s) e$ c1 S( Z8 H1 c       return $this->execute($sql);  
: F/ b0 K4 L5 K; P; F; q3 p) E    }
* V9 s. [" o3 U7 o- |; s从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
2 _: x% r/ ?. c5 d( R' p
) l7 v' o% W4 [1 q攻击测试:
/ D. u- q; S4 ^5 C- z1 F/ e测试地址http://localhost
* R$ t9 R  S  E  l/ {  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句+ E9 F9 D1 B7 a% u5 ]. |+ |. c

& L! I0 X. ?' j0 ?
3 ]2 Q9 x$ o6 {1 G5 R; m$ s8 r1 C- d+ A7 I5 W. ?6 P8 C

9 I! ]/ d% y# H5 G) f5 y- @$ Q( s- u, `) n$ Y% B- P

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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