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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告7 [; ?- n( C3 Q- E3 h% M) Z5 p) g
漏洞作者:skysheep
: Y& l- Q% l5 R' u& \0 |, a% g4 |分析作者:Seay
2 r2 c$ O, }; a7 c& M6 h' r3 c博客:http://www.cnseay.com/$ K) a9 u2 u# j# _; Y  l# j
漏洞分析:3 Q  {5 d/ V5 X
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。. D9 w  D5 {) F* X/ [
3 k! o! p. Z& J) u0 g5 ?: z$ ~
# [  B+ K( r0 }# c2 c

: r6 q7 ]# a; t7 v- ~public function account_manage_info() {  ' G# F! O; _5 D# h
       if(isset($_POST['dosubmit'])) {  . F* B- @0 P, a# i
           //更新用户昵称  
' M) r5 `0 ^6 D! M" L) D           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
$ R: G7 ~3 i% ?           if($nickname) {    C* C8 \( r* @3 e' @* d
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
% l1 Q. v8 r/ h5 F; @% P* V              if(!isset($cookietime)) {  
& e' Y& Y  t3 u% T& \7 Y                  $get_cookietime = param::get_cookie('cookietime');  
( U8 I: O/ l& ]. F              }  & |6 I0 T5 s( T; ~0 K/ S# B0 i
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  3 u6 g- K3 c- J) ?9 i! B' `. @
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
4 G* c' f9 U5 V6 A/ |% A6 ^* ^+ I              param::set_cookie('_nickname', $nickname, $cookietime);  * f* u* f$ \' D" `/ O9 A9 u
           }  2 F! ?, `9 J$ A6 k
           require_once CACHE_MODEL_PATH.'member_input.class.php';  2 o! C2 G! `$ v; N! e
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
  t" `2 E" ^; f2 z4 R8 h           $member_input = new member_input($this->memberinfo['modelid']);  
7 A# [. y7 Y- l- h8 m( i6 J           $modelinfo = $member_input->get($_POST['info']);  $ z( W7 i' |- ^4 d
           $this->db->set_model($this->memberinfo['modelid']);  % |. O) p$ W- A5 ]& i
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  % F2 I& ^/ z2 }$ J1 k
           if(!empty($membermodelinfo)) {  $ ~. g3 ^: H0 t3 Y  K  `
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
: i- P) b+ y1 D' o) R2 n           } else {  
* J$ V! R3 s6 R0 J1 R* m' Z              $modelinfo['userid'] = $this->memberinfo['userid'];  
2 w7 Q, s# y6 ?3 \& M" |8 I              $this->db->insert($modelinfo);  
- i- L) [$ f) g! @3 E           }
0 y% v7 R9 P  [. Q6 a2 T) I% g代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,9 M; Z- C) I7 i1 }8 R) u
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
) ]) S' F# R) n4 l% S8 F0 b+ o8 u( M
2 B9 L4 M0 p8 @0 E' \
: y) n5 x- T# q) T1 ~& R0 d0 S
; L" X% x1 u! Bfunction get($data) {  0 B6 w  A; p! Q  v9 f, v" z
       $this->data = $data = trim_script($data);  8 N. _6 X0 y* N, k, U) _
       $model_cache = getcache('member_model', 'commons');  
  E% F) ?7 ^" Z       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
8 |) Z1 T8 l0 t       $info = array();  0 S0 j  A8 b/ g+ I3 q
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
% ^( ?9 `5 K; O! ^: L3 R% y       if(is_array($data)) {  - \/ ]2 L" n! O- }6 Q4 q
           foreach($data as $field=>$value) {  
2 i% ^0 O8 q; }+ G/ }1 T              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
6 S0 t/ {6 _7 J" \" B              $name = $this->fields[$field]['name'];    Q/ {0 `* V8 j- i
              $minlength = $this->fields[$field]['minlength'];  . t0 F& t$ T; J  ]+ _
              $maxlength = $this->fields[$field]['maxlength'];  
+ a" w, a5 K1 P& ^7 e& U              $pattern = $this->fields[$field]['pattern'];  
* ^# V( {( O) u2 Q1 U9 V& u              $errortips = $this->fields[$field]['errortips'];  : D, l3 A. `$ q6 Y( f2 ~
              if(empty($errortips)) $errortips = "$name 不符合要求!";  ! Q, K6 N( T+ @9 I; i7 W/ i9 C
              $length = empty($value) ? 0 : strlen($value);  3 k, X9 B9 T) w5 S
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
0 T) n* w( t# Q" j8 u5 O              if($maxlength && $length > $maxlength && !$isimport) {  
' {+ L% G* H6 R& y8 r' z                  showmessage("$name 不得超过 $maxlength 个字符!");  4 h( v' y/ g* l( j
              } else {  
% n  e: k: z. x, A+ t: T& M+ G% y                  str_cut($value, $maxlength);  
7 D7 y/ K9 ^. ]) ]" G7 \( l# D              }  
6 h3 q& t5 f0 j              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
- y# I$ a3 q( R0 h                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ( a) `1 r- f# O3 k3 {. l! O
              $func = $this->fields[$field]['formtype'];  
0 T! f/ V5 m+ `; j; c              if(method_exists($this, $func)) $value = $this->$func($field, $value);  . q5 [1 x: W3 e8 `/ h1 K  n
              $info[$field] = $value;  
: b/ e3 _  R' V7 x           }  ( A# u$ ~* @0 A. S  q0 H
       }  
5 b' S5 x: _+ U5 s       return $info;  
7 Z6 ?+ A3 A8 u    } 8 V4 L( Z8 a; p- o5 B* u
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,8 b3 g) B& @9 q! M
* n6 N9 X* O, [& M4 }3 e6 i! h9 z
再到phpcms\modules\member\index.php 文件account_manage_info函数7 u8 m$ M: r# m; B: h! D
过了get()函数之后。
; y6 j) C$ F. B5 E/ ]+ d- \6 L* n6 p- A4 {# b8 s
5 B; _9 m0 ?/ J3 E; ~
$modelinfo = $member_input->get($_POST['info']);  
  i8 H8 W" e6 j  ^; J. @9 I3 z- h           $this->db->set_model($this->memberinfo['modelid']);  
6 _: S" o$ v+ v5 `           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ; N, I0 ?9 w/ O  l
           if(!empty($membermodelinfo)) {  
6 P4 u8 S+ R% ^              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
% y; {1 B& q0 n7 X  Q4 Q           } else { $ d6 t5 {; H+ Q- W9 V% I
直接带入数据库,update函数我们跟进看看
# H9 U7 ^1 H6 m! H
+ G# _' y9 }: b
& Q6 Z  W- v6 [. N" Lpublic function update($data, $table, $where = '') {  + q4 y* ~4 i3 `& V8 f
       if($table == '' or $where == '') {  
. M. F2 c9 j6 N( x0 L           return false;  / L/ I5 w/ @8 A1 S$ q9 i4 c% H( I
       }  6 z4 d7 Q4 {, O
       $where = ' WHERE '.$where;  
  l6 n" ]7 ^" @9 I3 {3 c2 V       $field = '';  % `, V3 F/ s/ Y
       if(is_string($data) && $data != '') {  
+ D" h4 ]% F' A0 @           $field = $data;  5 G5 m# O5 k" W- x4 o
       } elseif (is_array($data) && count($data) > 0) {  ; `8 R- E; n8 K- s
           $fields = array();  
9 j6 U1 o; o2 ]5 ^. H+ L* X           foreach($data as $k=>$v) {  : M0 E1 s- k4 S6 {
              switch (substr($v, 0, 2)) {  8 ^- ]: Q% }% O9 l8 l
                  case '+=':  
1 {" J; D; q+ S/ _6 K                     $v = substr($v,2);  2 S' O- |- b3 H- P/ t9 B
                     if (is_numeric($v)) {  
" p, f. {* @( }; L                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  5 f7 t( f9 ~7 w
                     } else {  
9 z9 L* b9 _. X. @& u9 X* N                         continue;  ' r+ R7 ^0 z9 t4 M0 u
                     }  + l/ B9 Q6 B; x
                     break;  2 `: a* }% ?* v" z7 @1 c+ a
                  case '-=':  2 i' f" e- `3 N
                     $v = substr($v,2);  
6 L8 |* r, r( M  P* h* U                     if (is_numeric($v)) {  
+ |/ y4 ~+ ]+ I4 d2 h. S, A% l                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  6 v1 I( H% E& I4 u) Z; O, |
                     } else {  ! K- u% S: o0 d. ?; A* V4 r: |
                         continue;  
* u& x9 W" l1 C                     }  
: `5 }$ k) M' h                     break;  * \; T0 F6 Y; V1 `
                  default:  : a3 j! ~# s" h) o
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  6 c  v; W' p) z
              }  4 f3 j( C3 ^  ?  l( i4 \1 v# e# d
           }  9 Z* Z/ @, g" b5 V
           $field = implode(',', $fields);  
, P8 Q, [0 m3 s. W$ s       } else {  % H! x! ?" d- c4 }1 ?7 Y
           return false;  
, r  |4 f5 K1 ]& j( q6 O$ `       }  3 A: p# Q4 x# ?$ I. I; }, b
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
0 U2 E9 r! ?, D0 d; U0 j       print_r($sql);  
$ f# P4 w4 t- F" X       return $this->execute($sql);  " g* `* }6 N0 Q) x; H) l* V
    } 0 h; r6 x; t  `; b9 e, ]
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。5 H7 w" U4 }3 e+ E# w

0 N( f2 \% Z; N& V8 i, ~4 ~7 i攻击测试:& G% ]2 k3 I; `" \; x: H" p
测试地址http://localhost! ~6 _5 E- j/ E# _3 b( g6 U& ?
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句, O* ]' b- k/ Y" B/ l1 {" H0 G

: Q! J2 Z0 B: D% G; i/ u
* n3 }. A' |2 \1 {( `( F" `1 a- `  z: d5 J' n0 s6 {

4 O# \/ p3 l0 Q/ ?& r0 u9 [% I; X/ f/ o& E1 k: ~6 {

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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