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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告5 b  W6 I. c& c! q; F) i& l" W
漏洞作者:skysheep
( p3 H" d" g2 Y- s; _; A( D分析作者:Seay
3 P- p6 a1 ~0 X: b- z" ~) p- j博客:http://www.cnseay.com/
7 Y9 C* Z2 \: A# V. `' h7 M3 Y漏洞分析:
$ S' \7 {% w5 O  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
+ [: J) ^( L6 }3 _5 }! y
$ s9 k4 }. U) k3 F  m9 P) L0 w: e! D) ~

8 M+ ]) ?( a% M% e8 b5 opublic function account_manage_info() {  
( d/ ~2 r- _- c4 N; j9 a: n       if(isset($_POST['dosubmit'])) {  
" N  h8 I1 q8 }1 {9 I           //更新用户昵称  / N9 u# [7 r- B  A- n% U
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  2 _. A7 R9 s* C- ~% o$ O) [
           if($nickname) {  
) ~- c2 P/ x: D7 v" o$ T9 K              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
6 H* z2 T# e3 i% a              if(!isset($cookietime)) {  ( \9 y0 s( O; P! P
                  $get_cookietime = param::get_cookie('cookietime');  
2 t- }4 k" P; r3 w0 J              }    ]) x$ F0 D) f9 Z: [# c
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
0 q* o3 Q% w: S3 k/ j+ C0 ^              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
2 u) x( S* V9 h: `& d& S/ r              param::set_cookie('_nickname', $nickname, $cookietime);  
" G& m7 G& r9 c9 @' G4 P           }  
, |+ t9 e/ F4 }% Q6 {           require_once CACHE_MODEL_PATH.'member_input.class.php';  3 b8 g+ n0 Y5 ~( N2 h$ v
           require_once CACHE_MODEL_PATH.'member_update.class.php';  1 Z+ m3 h$ L% Q  L- X
           $member_input = new member_input($this->memberinfo['modelid']);  
. O2 {5 I: M( q3 `           $modelinfo = $member_input->get($_POST['info']);  5 e" E0 H$ E6 s1 Y0 C
           $this->db->set_model($this->memberinfo['modelid']);    y$ @7 G% S' k
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  3 \! M9 u: N7 l6 q6 Q
           if(!empty($membermodelinfo)) {  6 V" f9 f- Y: O( L% D& I
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  6 o# V2 ]3 |7 s5 b1 k: Y# J2 z
           } else {  0 d4 }" U( q& B; d4 Q8 \: u
              $modelinfo['userid'] = $this->memberinfo['userid'];  
1 I4 y& I) f5 q& A: [* |" A              $this->db->insert($modelinfo);  ) x) A: b5 T! S" O+ P! G4 {0 @
           }
' m% O2 l! h3 G2 s$ z代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
5 ?8 n# J3 I* S, h- g; z在\caches\caches_model\caches_data\ member_input.class.php 文件中:: T  z# T8 X8 t8 o
- s# q/ \3 X: x6 I1 Q

. p2 o: ~9 x2 x 2 Z- W; U! F' C5 C6 @( B! w
function get($data) {  / T, A' m% ^4 a) s( f4 O
       $this->data = $data = trim_script($data);  + ~- C% z( L2 M" ~
       $model_cache = getcache('member_model', 'commons');  ' d/ k! O; y# R8 k
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
/ v( {9 F7 ], w- {7 N. Z/ n       $info = array();  . B: u$ S" q7 B5 |& T' F
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  # t! T( j  Z1 b2 m9 S
       if(is_array($data)) {  
) s. W: s+ g5 n5 S/ [% R$ x           foreach($data as $field=>$value) {  1 y5 _' O- V6 ^+ f' s
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
9 B' _5 m; Z+ a0 W* I              $name = $this->fields[$field]['name'];  8 A# @) V1 C: F+ N
              $minlength = $this->fields[$field]['minlength'];  
0 O9 H: \+ Q! `% y              $maxlength = $this->fields[$field]['maxlength'];  , Z: Q7 ~" \( {4 l- s) l4 t
              $pattern = $this->fields[$field]['pattern'];  
3 \* q+ S3 a! m5 {9 H  ^              $errortips = $this->fields[$field]['errortips'];  
1 h2 v4 h, M, l4 a# c              if(empty($errortips)) $errortips = "$name 不符合要求!";  
6 l" w% Y) y5 w! O% Q              $length = empty($value) ? 0 : strlen($value);  9 l0 @& f: _  k/ z
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
  I) {: j8 v7 X- W- }              if($maxlength && $length > $maxlength && !$isimport) {  
: W- e6 |+ F4 p7 b                  showmessage("$name 不得超过 $maxlength 个字符!");  / W: f2 {! p3 E: l. @4 k
              } else {  & ^/ ]) s  A4 X8 r5 J- G7 }
                  str_cut($value, $maxlength);  
) {& d' g& E$ B6 t              }  - a. j+ L5 }" m! W1 U& t" W: B
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  3 S- V! B1 o7 `$ x
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  5 I, h- h2 Y4 U% H- }, C: I
              $func = $this->fields[$field]['formtype'];  
; K9 m+ k2 q& L              if(method_exists($this, $func)) $value = $this->$func($field, $value);  / a* z2 N3 Z# t* v
              $info[$field] = $value;  8 P; W2 b7 P/ `- N5 W& j8 J( ?( r
           }  
- Y' U; M/ S: r6 q7 b# O       }  
" ~7 d* s$ m, k) w/ H6 @       return $info;  
2 Y  J  ^/ I5 x$ [    }
) ?$ K& [: q9 E* L: V. p0 s' G7 Xtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,* V8 K& f& V& X: D+ F1 E: |/ d( s
- N5 R  r* ^- {( e
再到phpcms\modules\member\index.php 文件account_manage_info函数
  \  o0 q) y5 e过了get()函数之后。
* O: X+ A7 o0 m3 ~! Q' d, z% `& _5 x8 }

7 d! m9 {* V; ^' ~4 M$modelinfo = $member_input->get($_POST['info']);  
3 ]# D% L# D: r9 b& W8 ^' L           $this->db->set_model($this->memberinfo['modelid']);  4 v; o: V6 R* o' O7 C
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  1 J! N+ |; [% r( C8 s
           if(!empty($membermodelinfo)) {  
% i$ n" z+ J) O              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
0 W8 ]. q) |4 H           } else {
% G% i" d0 [5 w* B7 u+ Y! t直接带入数据库,update函数我们跟进看看
% U+ E7 O+ R/ b% }# y( c& E. R, d  W9 x. F% t
0 L2 D1 h. r9 _1 Q
public function update($data, $table, $where = '') {  ; M$ E' k) P& G/ ^  J
       if($table == '' or $where == '') {  # n# @* F( i& E3 g5 s8 Q$ x
           return false;  ( g5 `5 s( ^. s
       }  ' {! q$ @  r; I0 P7 G. J
       $where = ' WHERE '.$where;  
1 L/ z' ~9 ?9 T/ s4 B       $field = '';  
, a4 V; Q9 Q1 }1 ?2 W7 _/ J       if(is_string($data) && $data != '') {  ; Q0 u; j5 L- g0 e- L. `" X
           $field = $data;  
6 U+ ]  H# z7 C. H6 j& P       } elseif (is_array($data) && count($data) > 0) {  
! R) c2 h; Q: r! }  Y" P           $fields = array();  
# B% P. w  `) u8 U           foreach($data as $k=>$v) {  
' o! }/ r( |. X! y  g6 b              switch (substr($v, 0, 2)) {  
9 Z% E# i! k6 Z2 b; ]- G1 C5 `4 }                  case '+=':  / p4 w1 f) @$ G/ z, x3 W9 X3 {
                     $v = substr($v,2);  
0 j* P' T. D4 M' W                     if (is_numeric($v)) {  
8 j% ?0 W8 [; x% W) @                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ) h1 s( ?6 B% N- i8 F
                     } else {  # y4 k" T" t& m1 ]" P7 w. p) V5 V
                         continue;  3 o7 n' d  e3 J
                     }  / {( r# J8 V3 t0 ?* G) w8 q
                     break;  
6 _( F, r# i; Q# @3 }                  case '-=':  
* j  G1 Q( L8 v5 @5 V/ V8 o7 [1 O                     $v = substr($v,2);  $ _$ G$ s7 s/ l1 |  N; o  }
                     if (is_numeric($v)) {  
; N' y5 R, z& R0 Q& b8 f                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
& Y% H; F2 P! O/ t* c$ l                     } else {  " z4 @- D: Q2 @! ^" q5 w
                         continue;  ! t3 t9 [% u" x: ^1 K" {
                     }  ! z' v- K: W* c+ L
                     break;  9 T& C& U' X3 K; \
                  default:  $ h1 s8 [) ~9 H
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  0 m. N0 d' S: V; ~& J+ m% I
              }  
' B: e2 O4 }7 ^" ^2 ^- j  ]. e' ]           }  5 }# X3 c8 ^" }( w" S% P+ T
           $field = implode(',', $fields);  
0 I7 h' z2 H  c) r$ U7 L3 Y2 A       } else {  2 Q* ^' Z% o/ m! C3 P' _0 b! w
           return false;    F+ E+ X/ @+ E* ?3 K: [% k4 Y& Y
       }  
2 y" s2 C3 D- j' W       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  6 |. Y( g' ~0 ^/ l! h& l
       print_r($sql);  5 V5 o: D- Q) i0 @' c0 O% z
       return $this->execute($sql);  0 E3 i5 E: x" k1 V8 n
    }
( S, l+ Z9 I% L# x  t2 |- Q从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
, |2 ^; K  C# U, Z' R) A1 y
3 Z" Z. Z4 y$ ^5 O攻击测试:7 q' y9 o! q0 e# N  b8 a
测试地址http://localhost
! X2 \0 D; ^: y+ H3 s5 ]  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句# A; O) J, \- U" R& B' Q6 B

: ]. Y, |9 g" `* t- ]1 ~" Y1 y 0 s8 {& w4 a6 _0 F! w8 k* J
( h" X2 R; O  k1 z

3 u1 j5 G  E$ U! U: i
9 \8 r) G8 c/ U6 {8 d9 M

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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