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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
9 t7 J6 ~. v, Y漏洞作者:skysheep6 r4 t+ t+ C: T; V
分析作者:Seay
) d0 M# w; X) g7 V( f9 _# b2 m9 B博客:http://www.cnseay.com/
/ D; S  `5 h+ Z7 e. Y% L* s漏洞分析:0 K5 o5 i; S. W6 @- r
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。! }% @0 M; D/ }- O

" E8 j/ D# i# b6 L- s: R$ ~
: u7 {8 h/ i2 s1 g- e
2 g4 U6 G& H/ R% m: t- l* @public function account_manage_info() {  
! c  {# k$ S; X' J2 l/ [& T: r       if(isset($_POST['dosubmit'])) {  
$ Y1 K, N! I2 `           //更新用户昵称  0 @' |% W9 ]& ]4 s2 ^% W: @
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  & k$ J/ J9 Z& Y) d  g
           if($nickname) {  ' f0 [+ q% ?& D3 l# b  k7 x
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  & q! M1 x- [8 @( W9 ?- r
              if(!isset($cookietime)) {  
' W% t1 I0 Q& Z% [0 G) b* @7 Z) ^                  $get_cookietime = param::get_cookie('cookietime');  
. e4 R3 g/ e9 M, y9 W, j              }  # s8 b9 ]* i( Q
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
6 m; @% i( ?  o              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
$ U8 h+ X- H8 k5 c7 j  `              param::set_cookie('_nickname', $nickname, $cookietime);  
6 f# x6 S8 N3 e* X( j# `1 F           }  
; T8 e9 n. t! h2 K           require_once CACHE_MODEL_PATH.'member_input.class.php';  
  L2 ~2 e5 L. q* X% g( J1 }           require_once CACHE_MODEL_PATH.'member_update.class.php';  1 }; M' y( R# y7 U
           $member_input = new member_input($this->memberinfo['modelid']);  
# G. `  w5 ~, V6 f           $modelinfo = $member_input->get($_POST['info']);  * f' p9 ?' P. b# l+ }
           $this->db->set_model($this->memberinfo['modelid']);  
( Q1 m; w- w$ h: F& F+ }9 j           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  0 I8 S6 i: ]* ?+ U  u* C; [
           if(!empty($membermodelinfo)) {  1 {* ?0 x" r- r/ C6 ?
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; s7 g- ~; J5 N
           } else {  4 m( Y) Y  q6 C, ]3 ^/ r4 _
              $modelinfo['userid'] = $this->memberinfo['userid'];  - I1 w$ E; N! C+ F
              $this->db->insert($modelinfo);  / A& F3 M5 R/ Q' T# n' @' ?
           } * _7 ]8 Q* G2 l4 L, }  v# f: f% V
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,4 m: v2 J" [- K7 }4 Y" B0 x; P
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
1 @& T: m  |8 B. K& Y8 u; J  k: ^0 u4 J" ]3 `

' m4 C/ R8 R; |: V% D- N
. x* a, L+ m/ g6 lfunction get($data) {  
9 t& U4 B/ g6 P  ~       $this->data = $data = trim_script($data);  8 F. l1 O, Q9 u# Z2 S
       $model_cache = getcache('member_model', 'commons');  
  |: P  @! k0 q; l/ j2 j1 |& F       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  : A7 `1 u; {3 l& G8 V, e, h
       $info = array();  $ e5 h- o" q* Y  J( n
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
1 f+ ]  k: b: _3 }; ^       if(is_array($data)) {  ( C3 X- q9 ^, J' t7 k( d
           foreach($data as $field=>$value) {  
1 Y8 V+ _  M- o              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  4 y; e+ {' D; l( b0 e* ~" A0 b5 ?+ b0 w% t
              $name = $this->fields[$field]['name'];    B, U6 G0 s* }3 w; u
              $minlength = $this->fields[$field]['minlength'];  
5 m; v6 m, Y6 t& ]9 W& \              $maxlength = $this->fields[$field]['maxlength'];  ' O6 p/ ?7 e1 N. c6 T
              $pattern = $this->fields[$field]['pattern'];  
& k8 K5 M  S& R  N1 s0 ]              $errortips = $this->fields[$field]['errortips'];  
/ I% l" c! O- f. {9 [. [) M, v4 G3 s              if(empty($errortips)) $errortips = "$name 不符合要求!";  ( [1 o! {, _* \- r, p9 s3 |
              $length = empty($value) ? 0 : strlen($value);  0 Q5 X* l$ p/ G5 P& `! F
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  0 U- O: g* }0 u! U- G+ g( i+ M
              if($maxlength && $length > $maxlength && !$isimport) {  
6 c7 k- a8 I: |& d0 v                  showmessage("$name 不得超过 $maxlength 个字符!");  
1 X1 l0 W. M0 f$ D9 c              } else {  
' N4 u$ `3 O2 f' z5 m; z                  str_cut($value, $maxlength);  3 H" Q& F( _- x* J8 n/ E
              }  
4 ^0 `7 s/ l, N5 m' W              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
/ x4 W# F7 m% R                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
: B) R% j: {9 `* ~& @              $func = $this->fields[$field]['formtype'];  
. I  S# t* A$ J9 o5 D+ E& ~6 L7 l              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
- |9 H3 X; {! I4 [  W' P( O6 Q              $info[$field] = $value;    z6 G/ L! |. l5 y* U
           }  2 P) P" L' P5 E
       }  ; Y: n% q7 I! d0 S8 a9 l
       return $info;  
1 ^2 Q4 a! b4 X% L5 {" i    } 9 a) \: N) Q" G' X0 O: w5 s
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,8 {0 R; `% k; B; e
& S0 v, j0 I9 [# s
再到phpcms\modules\member\index.php 文件account_manage_info函数
+ U' c9 v) `0 J' l过了get()函数之后。( @" c* j  L" o' a# @
1 P* `  C& G+ c" N

$ W- K& C, |% u) s3 _# @' k$modelinfo = $member_input->get($_POST['info']);  
5 ^+ R& N7 ?9 Z# I0 M2 i' e) [           $this->db->set_model($this->memberinfo['modelid']);  $ _8 Z! z1 J" c
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));    G; z7 y2 Y6 s" I  B$ c5 T
           if(!empty($membermodelinfo)) {  
9 U4 ?* y5 N: P" P: j7 W' ]; M              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  5 G/ M( x/ s$ Z: b: g
           } else {
7 b' l- ?$ a1 h5 O* V. r直接带入数据库,update函数我们跟进看看
' ~: A6 S4 |  Y3 R, @. M. F1 a& g: h& o0 k
1 \& m8 X% k% K/ j% E
public function update($data, $table, $where = '') {  
! P% p9 K+ \/ {2 h: ?2 Q       if($table == '' or $where == '') {  
: u" Z2 z& Y' j/ e. B6 K           return false;  ( `0 T; K" E) U2 Q$ ]" @  X
       }  9 }4 g  _; c' H9 O$ J$ S! G* d
       $where = ' WHERE '.$where;  6 q6 n4 d* a, m1 h; K
       $field = '';  
8 s9 w' T" K& B       if(is_string($data) && $data != '') {  
1 y+ X/ q& A) X           $field = $data;  
& D) E: j2 K( m       } elseif (is_array($data) && count($data) > 0) {  / D  _; k- u3 D+ c
           $fields = array();  
. V7 P& P' }8 t2 A& }           foreach($data as $k=>$v) {  
9 Z: h: O7 Q7 j4 V% ]3 `6 \  f              switch (substr($v, 0, 2)) {  4 c" |: o/ s& x4 t" \2 n, J& K
                  case '+=':  6 R; J8 g2 g. W! k
                     $v = substr($v,2);  
8 p+ g9 b9 H7 O- V$ V. k                     if (is_numeric($v)) {  
7 J8 a3 G% G' J* H8 v; z6 W                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  4 M( c2 g, _1 \" X. s
                     } else {  
( K# T, F( A) |8 ]$ x                         continue;  : @* q# X) W; `# I" l+ H
                     }  ' @3 D7 ?2 L, v" O+ b" z
                     break;  
* k5 B/ m; G- f4 c6 I' m                  case '-=':  $ n- ~4 ^7 V5 x- I. c) }2 g$ K
                     $v = substr($v,2);  
0 t* a1 o1 }$ Q! y  ?                     if (is_numeric($v)) {  : S9 e1 j" R# d
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
3 ]9 n) `9 l, ?' Z3 ~- B                     } else {  " O9 A; Q1 V* l  u. p  J- M
                         continue;  5 F3 n% [- B; H4 r; J- [- e
                     }  
3 F& N: s6 H/ O# S! w                     break;  
4 C) i& D/ O2 e                  default:  % R& H  X8 q2 i1 G
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ; b. F  L7 O/ z# T
              }  
. O8 g) k6 k& O/ D           }  ' w% D! K  b4 }5 R# z3 s, ~
           $field = implode(',', $fields);  
$ q9 L. M/ M4 M# F$ u! ]  M1 A       } else {  
, B5 a3 W4 W  e           return false;  
: s0 ]2 z3 K$ y/ J/ P* H) m0 y& L       }  
8 R5 W: n2 ~) h( q% I       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  2 }# {* m3 S7 L" u
       print_r($sql);  - i* L2 R6 @: p7 ~3 ^8 E$ R% v# P, W
       return $this->execute($sql);  
4 F* U% z2 j6 N& {  F. H    }
7 s: V0 }+ k. D* R7 L. d3 z7 a从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
( c- W3 l" B+ w
* F% O+ L; _" Z" s+ z2 X% C8 F0 N攻击测试:& H( N2 ?: L9 k/ ~* e+ t6 c; N
测试地址http://localhost. w) w. L8 f: E# l' \& t
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句7 v7 v# m$ e+ C( G/ a

9 U; W' w1 h9 R9 j( R: V( n " D  ?/ F/ s  q' z- ~3 F6 B

7 d. z& i" E; }- t5 g4 j* `: l0 z: x: B. |: x5 D# N5 b: C

8 A3 {) B2 Z" v4 Z. ?! g% [

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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