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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告, M' y$ k1 |, x. k% a& S
漏洞作者:skysheep
0 x5 B1 {. J* [- c- v/ f) C$ h分析作者:Seay8 @3 [" t1 X3 M% J. b
博客:http://www.cnseay.com/' Y6 \/ S3 _9 W3 G! l6 g
漏洞分析:4 i' @2 L1 |5 I/ t; F
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
+ V" v6 U, d5 e3 e! U7 B' v
) L3 M; y0 x/ E" A
8 L% J/ l3 b) U ( n! N- w7 E0 y- h& g) ~
public function account_manage_info() {  / v+ A, J" Y% _' g+ a% }
       if(isset($_POST['dosubmit'])) {  3 |! m0 R( k9 Z% }& s
           //更新用户昵称  / \6 u+ N, c) s% [
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
9 P' z- r. ~6 W           if($nickname) {  6 M" {  E: @2 T9 _
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  $ e9 v: k/ Q5 g" t) H
              if(!isset($cookietime)) {  
, `" m1 L1 m+ m! l% d8 ]9 P                  $get_cookietime = param::get_cookie('cookietime');  ( v7 j! q8 Z  v) ?; y! F
              }  
7 L7 w% J7 O/ s              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
( \9 \8 h  f+ T2 H2 T$ c# ~              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  5 H: o: b: l" C8 t$ M
              param::set_cookie('_nickname', $nickname, $cookietime);  
4 U9 J# W; H8 P3 y0 P           }  6 Q" y( d! r/ u8 I$ k
           require_once CACHE_MODEL_PATH.'member_input.class.php';  1 l$ K/ p* z% p' V
           require_once CACHE_MODEL_PATH.'member_update.class.php';  " {3 v5 F1 e) Q' D% D7 l# M
           $member_input = new member_input($this->memberinfo['modelid']);  . S( r5 P, Y- {
           $modelinfo = $member_input->get($_POST['info']);  5 y' u, |' T4 u
           $this->db->set_model($this->memberinfo['modelid']);  4 y& u# W8 o, r7 Z3 r+ V
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  / w/ b. s6 {5 \  G* t/ d9 N
           if(!empty($membermodelinfo)) {  / `) |2 f% J) \  ^) ]
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
7 n+ W. M) |. y% @2 ~' y+ t           } else {  - J9 t* Q8 Q! ~1 E+ G2 d
              $modelinfo['userid'] = $this->memberinfo['userid'];  , X; c* o0 S4 L1 d8 x$ [
              $this->db->insert($modelinfo);  + l- [$ V& m9 x& J3 S& l
           }   i8 a9 I, q! c! j# C  z( J
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
% X- P0 @0 y$ E: ?% z& S$ U3 P2 T在\caches\caches_model\caches_data\ member_input.class.php 文件中:
3 r9 E4 O) m' A4 \9 Q) ], y
: Z* _1 h0 |# }# v+ Q, S, e/ a
3 u/ q5 Y; D$ n  }- l6 D: l / y# E9 }+ T* q. ~, b
function get($data) {  
' h# L4 U4 k& Y3 Q. F" o+ b/ H( g# L       $this->data = $data = trim_script($data);  
" ?0 P& f1 G  l, m8 y9 M2 x) q       $model_cache = getcache('member_model', 'commons');    m8 L7 |, H; ^# I0 V1 N; I
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
5 _/ ]; W, L3 }1 |, n       $info = array();  
$ ]- q: J& e7 q/ B" n3 g: M       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
6 M4 T; f: E0 U7 x; F       if(is_array($data)) {  
0 b5 z3 c% J7 f4 D1 E4 |9 \           foreach($data as $field=>$value) {  2 G* R- B; d/ |  b# p
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
* t- a6 \; Y3 A) Y4 C: ~              $name = $this->fields[$field]['name'];  
3 \1 a, \$ ~) ?7 ^              $minlength = $this->fields[$field]['minlength'];  
( j" A9 F, }2 n  i1 e              $maxlength = $this->fields[$field]['maxlength'];  
' C. i) N, @+ z: w. w5 T. c) v              $pattern = $this->fields[$field]['pattern'];  
4 C4 d3 D" |2 {/ h% }( p0 {              $errortips = $this->fields[$field]['errortips'];  , i' S3 K& {' k- t
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
+ ^3 W  X, ^; p) l2 [. n2 }              $length = empty($value) ? 0 : strlen($value);  
3 O' e4 B; o$ h# j% b6 M              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
6 l  P: ^7 F1 W% f/ I( V' w7 \: V              if($maxlength && $length > $maxlength && !$isimport) {  
. F! a; V# _- L, C2 x% u! r+ e                  showmessage("$name 不得超过 $maxlength 个字符!");  7 I2 }7 H6 _% }6 y
              } else {  
& Z: h3 v4 `  b6 n7 j                  str_cut($value, $maxlength);  
2 [" X- L# C- q- @" h              }  . _: p. T; m; {0 e; e5 n7 S) j
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
; q3 j1 u9 }( J4 y$ x                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
1 A8 E  }6 v' ]9 e              $func = $this->fields[$field]['formtype'];  
: t+ Q$ l$ }8 C; j) j              if(method_exists($this, $func)) $value = $this->$func($field, $value);  5 x* o5 i0 s. W3 @: k/ u, F0 F2 C
              $info[$field] = $value;  - t9 _' ^% q2 `6 N5 F
           }  + O$ O7 J8 \. t0 I6 b7 l: T4 D
       }  
+ c( W, B* O( @! V" n* G       return $info;  9 K' w4 ]9 G0 e  f* a8 I
    } ( p& u9 c$ b$ @7 W" a4 A2 N
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
& ~/ n0 O  [/ d( J- V
, l. x/ d, ~6 j- X再到phpcms\modules\member\index.php 文件account_manage_info函数
- ?$ {6 D1 s: U$ g5 `3 m) p; M过了get()函数之后。0 t' O  A$ p1 j- b2 o4 U' l( T8 n

7 q# h! R' s. a! z; _; s& U
- \3 D' y* m+ C6 i; O8 ^$modelinfo = $member_input->get($_POST['info']);  
' Q% ~  Y) D3 m+ x; G6 O$ @7 r           $this->db->set_model($this->memberinfo['modelid']);  " Y( t$ z9 t/ ?# l# D$ o
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  . L1 `/ C2 @0 u' F
           if(!empty($membermodelinfo)) {  
/ J2 d  |1 q  o/ S7 f, y              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
0 b) V+ I: ]# C8 `4 I           } else { 9 g; v1 H! e' l+ `
直接带入数据库,update函数我们跟进看看
9 C3 i3 B' J* O: N: u
( x0 U- S+ A% o) Z: c9 S
- s, G/ f8 I, [$ ppublic function update($data, $table, $where = '') {  ; b. ^7 V1 L3 C6 T* ?
       if($table == '' or $where == '') {  8 k# e. [" b2 ?; b2 Y9 R+ L
           return false;  - B1 F, f5 [( C8 F1 F  c
       }  
: Q: [8 ?2 X) M4 y: Y* I       $where = ' WHERE '.$where;  7 {/ u& |% `' ]- S$ G
       $field = '';  
% k- _" ~/ ^3 k% A8 l) p6 w% z       if(is_string($data) && $data != '') {  
/ J( t7 T9 r( j- H8 O           $field = $data;  
; B, k* U6 ~; M0 U       } elseif (is_array($data) && count($data) > 0) {  - [0 }  a! f' [4 l
           $fields = array();  : r2 W4 n" q1 ~% y- E" \
           foreach($data as $k=>$v) {  ' v9 e2 ?% ]% P
              switch (substr($v, 0, 2)) {  
3 R  ^6 J! K/ j) m5 A$ E5 U                  case '+=':  
6 ]6 q3 M1 N4 j8 H1 k9 r+ O                     $v = substr($v,2);  
! f, E6 ?$ R9 R, A- n) B# C                     if (is_numeric($v)) {    Q* S; M( k6 t; @# Z/ A
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  , k, B, w. n; F/ q
                     } else {  
5 H' x: Y* O1 R- j  V- Y  t                         continue;  
& Z% e6 \7 O8 f2 O                     }  4 U) {+ J! |( H* {
                     break;  # u: O# N& {$ g. d, Y
                  case '-=':  3 z/ r2 a0 Q' A& k8 }
                     $v = substr($v,2);  + h# j) o7 m# a2 k
                     if (is_numeric($v)) {  - _% O/ }! Q. l
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
4 d6 Y# B" U$ U, Y$ Z- p. x( t: Z: M, e                     } else {  ' b/ O, [; U1 K6 |) Q; I- w' L. p8 l% f4 i
                         continue;  6 D& ?( G" Y. _+ b1 a+ D$ n; b. B
                     }  
% c. t6 L6 S/ Q- u, \: u                     break;  1 r# _* y& l% {% _3 c
                  default:  
3 n" m' C- d" u+ _                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
  S. L/ A6 u8 Q5 ~( V! j; X* v& ]              }  ) v' G2 a/ f& @  Q3 N0 X
           }  6 i& s" U6 s  q+ {! [
           $field = implode(',', $fields);  
- s" U! {$ M- j       } else {  , b) n5 S. ]6 S! J, E
           return false;  9 `6 S4 G' ]' {6 h! y- w5 S* A
       }  0 J2 j1 y, _" c' }
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  / B) ?& ?: e0 o/ t
       print_r($sql);  
7 t" [9 }$ ^! ^5 L/ ~       return $this->execute($sql);  
/ ?8 v# Y$ z3 `: F& H5 u6 x    } & N( S4 f  s. {7 ]4 _6 u/ M
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
- Y  I  l$ ~" N( P' \; B+ m
( @& \* F. t. R- F6 g攻击测试:
9 O% i' k3 [. l+ Z! j7 Z1 {测试地址http://localhost
( h0 ~1 O/ b. g6 J7 c* }  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
; i" n( u9 h$ c7 z* ]! ^
8 |! H; R; h9 @% g 8 L4 D# |4 @$ b* z, a" N

0 b3 G. m. ?* n# i8 J7 X$ q0 j9 Y1 x/ K$ _* {, K

, d; I7 x: L1 E% V/ E

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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