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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告9 G. t7 {) _; b, M" c' K+ O# q( ~# |
漏洞作者:skysheep
; K2 _! j, k2 n& ^: A/ V8 U+ E1 ~分析作者:Seay
2 K0 ^) o4 ^5 I0 E! q1 [6 a博客:http://www.cnseay.com// m! _) t+ C* r& t3 K1 g
漏洞分析:
% ~4 b, Q# B  K5 ^) Y- e  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
9 X8 ~, E5 n- `# y4 S" I
; F& ~7 L1 p* |: F% c* l6 O5 F4 @0 J1 `) L& I+ l$ X3 i
' G0 g, I8 o4 ~6 |9 n5 x
public function account_manage_info() {  
1 F# D* m) _$ R( ~4 i2 C       if(isset($_POST['dosubmit'])) {  * W+ V, S8 ^: k+ Z2 t/ u6 v
           //更新用户昵称  & M% A; {" |8 ~: _7 g; v; A$ s
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
  H5 m6 \% q2 _' Z3 W8 U" G9 y) V+ b           if($nickname) {  
1 Z- @8 ]3 ^4 C) y& c              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
: U6 X$ }8 ?9 b! Q9 a4 U2 e; U              if(!isset($cookietime)) {  
7 U& F9 k8 k( ?                  $get_cookietime = param::get_cookie('cookietime');  
) r- N3 N; O1 J+ R              }  
8 E3 N+ Y% P4 C              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  6 ^5 C9 H6 a% c$ _$ x( A
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  0 R8 y+ Z5 c' F" t( f+ q
              param::set_cookie('_nickname', $nickname, $cookietime);  
' Z# S3 r1 d# C           }  ( }0 [# k' A" s+ {& p
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
2 q6 o! [& M( e2 v3 p           require_once CACHE_MODEL_PATH.'member_update.class.php';  7 e2 @1 f5 F& E: H
           $member_input = new member_input($this->memberinfo['modelid']);  
2 k3 H3 v& R" b0 ~" N# S& j) P           $modelinfo = $member_input->get($_POST['info']);  
' {! x6 ^! A& l6 ?! M$ M& }           $this->db->set_model($this->memberinfo['modelid']);  0 o! t( E) o* ]1 [
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  , v4 |) F; f) Q, W) [
           if(!empty($membermodelinfo)) {  
8 p" J# [+ i, J5 z" C# @- f. G' A              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
3 q# f* S) A$ e4 X8 X- N" _; y           } else {  * L$ q1 e. y) O
              $modelinfo['userid'] = $this->memberinfo['userid'];  
6 z8 ~6 x1 ^! p  u, A9 S, v6 l              $this->db->insert($modelinfo);  
& w  S6 \' B* F" C           } 0 M. ^" O4 E( I; S
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,( s3 ~% q: ]) N4 l3 O
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
& S: u* ~  l, c6 \
" b/ h/ S1 `+ f4 i0 S5 f. b
% B4 o' P. w8 r% b$ L6 d; Z
  X( s! E# w4 Q( e& Afunction get($data) {  , K9 Q& l$ \; q5 ~" O9 }: i% `
       $this->data = $data = trim_script($data);  + M7 D+ m) M" ?% f4 e: o( T
       $model_cache = getcache('member_model', 'commons');  * b' ~9 Y! N% t' k3 P- O* M8 O
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
! W1 Y0 v) v* u7 }2 {* w       $info = array();  4 ~3 W' ?3 b  U$ A, @
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
+ ^, `# }+ c( ?- Q  z* u/ K: ~       if(is_array($data)) {  
2 ]* o* p  D& K           foreach($data as $field=>$value) {  
7 ]/ p7 R6 D! }4 d: l              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;    u! k. I2 S6 l# a5 \  N
              $name = $this->fields[$field]['name'];  ' {  y  N) U$ z9 ~$ T/ w) ~
              $minlength = $this->fields[$field]['minlength'];  
% l9 [2 `& P/ O              $maxlength = $this->fields[$field]['maxlength'];  
$ e+ ?) E: z! ?$ E2 g  V              $pattern = $this->fields[$field]['pattern'];  
# h. B; t/ D4 V' m) b! W              $errortips = $this->fields[$field]['errortips'];  
* Q( F' ^$ I' m) t! W              if(empty($errortips)) $errortips = "$name 不符合要求!";  7 N7 J1 r7 b9 `, ~- t' ]' f' o
              $length = empty($value) ? 0 : strlen($value);  , I) e4 Z. H  g* P4 B
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
, B4 v8 W, A1 r( N              if($maxlength && $length > $maxlength && !$isimport) {  
& T' k$ D9 f: L. R7 U                  showmessage("$name 不得超过 $maxlength 个字符!");  
" k$ J4 S, `- f! q- n6 `              } else {  : t6 v' ~) M( w0 V. i$ J
                  str_cut($value, $maxlength);  ) p2 Q$ E# o8 D1 S
              }  
' N5 K" R+ {' h0 L              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
4 v9 [3 g" p+ r" d" A$ B                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
! R* S6 s1 @/ ], ]' o              $func = $this->fields[$field]['formtype'];  
0 n! P9 Z5 j6 m              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
, y) P* a. q! m              $info[$field] = $value;  ; A$ N- _1 C5 g' d) F2 }1 W
           }  
$ m$ g* I; H+ q0 n$ x) _# L* x5 [       }  
! x: c, i$ I9 p0 s9 @3 B0 j- a6 I       return $info;  / m3 R; U, A7 @* J+ `
    } $ s$ L; d5 X* a/ f
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
* C1 B/ O  ^. E5 y! M- K" }' ^  ^8 M
再到phpcms\modules\member\index.php 文件account_manage_info函数, g5 @, H+ a4 Z
过了get()函数之后。: x% e7 e8 t/ J$ U6 j3 P( r

# i9 v9 t9 C2 h7 A' T
6 S$ g0 Q4 [; E! ~* I$modelinfo = $member_input->get($_POST['info']);  9 N9 M# e* A8 S4 V( M3 G' p. e  V
           $this->db->set_model($this->memberinfo['modelid']);  0 j) S7 [' D. I. T( r( |
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
8 {1 ?" p0 C# _) N5 Y           if(!empty($membermodelinfo)) {  . J/ V' s8 f$ F( I# b2 y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
% T! R; S$ g, |/ B& n           } else { . W# u" Y6 ~4 A* m" f( p
直接带入数据库,update函数我们跟进看看  b# D, T5 r  V# S, E( @; c& G% f
* D: ~% h5 E* z- Y; Q

' M+ O4 o4 U/ G0 E6 r/ n7 opublic function update($data, $table, $where = '') {  ' m1 r- k2 i) `9 d2 M
       if($table == '' or $where == '') {    K( a& f/ c4 {
           return false;  
3 w6 m8 N" _% J       }  
; U. E$ J* q. t       $where = ' WHERE '.$where;  $ [6 A2 Q  m2 H. b; Z* n4 u% o
       $field = '';  2 a1 u5 J- {/ u3 L" w' l
       if(is_string($data) && $data != '') {  
+ a6 r/ P+ f" T' @  @( V7 `           $field = $data;  
3 k: T2 Z4 o  L  o- f3 w       } elseif (is_array($data) && count($data) > 0) {  
/ ?9 e* e! F' S& r           $fields = array();  9 J0 z; \* v3 y% e
           foreach($data as $k=>$v) {  
6 k! y5 C. C0 a2 R+ x# E* b2 r( }              switch (substr($v, 0, 2)) {  ; B: p8 x( Q; l( E. R/ n
                  case '+=':  
0 u5 u$ n4 g& {+ S6 O                     $v = substr($v,2);  
; K& @/ D' R: E, T: w                     if (is_numeric($v)) {  4 y" O$ \$ U- G- g3 q
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  " m" v! g/ V: d+ j+ ^( u' M
                     } else {  ! C- V$ o, Z. D' R+ f3 i3 ^$ I$ {6 s
                         continue;  
9 Z8 M+ A1 V% c5 R& u! {$ A                     }  ( e; X  Y2 T  l% i
                     break;  9 v. K( [! M, t$ ?; \# M. N: U
                  case '-=':  : m* b2 G7 k! ^2 B! H/ @
                     $v = substr($v,2);  
% q. Z/ e7 Y- j: U& i2 b                     if (is_numeric($v)) {  8 d6 m, |. E- r  i. F! O
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
7 @" q1 D5 e) z. V9 t# T- G4 W: d                     } else {  
& b$ b; J2 S! r* \                         continue;  
0 F) a' p1 v) {5 q) i/ v/ i( I                     }  7 ?4 [; J8 t, B
                     break;  
/ j+ F$ J! m- |) a                  default:  
3 ~5 U2 y, W3 o* c! t+ K! o1 A) C                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
$ H$ S9 _9 g, z1 T              }  & W8 G2 H% `) Y3 F% t4 w2 t
           }  
. z$ ?# b6 ~% p. g" c  K           $field = implode(',', $fields);  
; i2 b4 E0 p" G% e0 g' B! J       } else {  # A+ m  g+ W/ z( R% B
           return false;  . a. A1 F4 K: D6 k: {, f3 m; S
       }  & z" S; s2 C6 ^
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  . e: k9 J# E# J9 S8 r
       print_r($sql);  
) O3 l5 b7 O9 p6 @       return $this->execute($sql);  ' w" U* e& H- G" e( p; ]8 i# F" O# U
    }   d( w; S6 V, ?: Z+ M5 c& h: v
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
; O% y! B7 s6 |2 F# D6 G
/ t1 }9 |$ C6 Z6 B- u攻击测试:9 b; e8 m+ W6 l1 y
测试地址http://localhost8 D: N# V5 M5 H, I# I, v- Z
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
9 ?% z- [& C1 T3 ?5 a
6 F( c6 h1 J+ f. N0 y % _6 J; m, @: ]3 V
  }* t" r& X" p

( }0 T  v" Z& K7 c/ `1 \3 r! j6 K$ N( R: l" k3 @

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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