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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
5 ~- A; Y1 c6 w' B& ~漏洞作者:skysheep
/ L9 z% r1 |/ T' z* h3 r* O0 m分析作者:Seay2 T2 r% O9 L6 |7 B/ Q5 a
博客:http://www.cnseay.com/
4 F9 C9 A. H9 M; I9 v- N8 S" @漏洞分析:
4 u. b- W9 E9 H1 u  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。  q% d3 [7 ~. ?7 B$ |6 W

$ [; p6 Y: F& u4 ~* V7 x3 q
/ g. \% H- I( X" z2 p5 ^& t
/ Z; m* {# V5 E2 o( gpublic function account_manage_info() {  $ P7 ^3 p0 Z1 Q- @9 y2 S
       if(isset($_POST['dosubmit'])) {  
1 C! Z4 {" |* {; Y. s6 |           //更新用户昵称  - U7 ?: t) g; X' w/ y+ U
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
* a/ T" [1 ?+ ], O% i           if($nickname) {  
: e' t9 o# x% W( A" o              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  + o# q) [! P% z7 _" E, ]4 ?+ I
              if(!isset($cookietime)) {  
. t3 L+ s( n& v2 O! l5 @6 b                  $get_cookietime = param::get_cookie('cookietime');  ! _- }. M7 }! x: y( \" L
              }  
2 e9 ~. z2 m0 S. K# G              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  9 P- \/ g, b+ {% `2 C
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
" h+ Y; E' C1 u% j" l6 x2 A3 Q              param::set_cookie('_nickname', $nickname, $cookietime);  + a' q' i' |# ~- y5 Q6 U" O
           }  
% K* @' k. e* G           require_once CACHE_MODEL_PATH.'member_input.class.php';  
0 W( V) W5 `% a. F, q4 _1 e           require_once CACHE_MODEL_PATH.'member_update.class.php';  ) C3 m7 w6 F0 ~" r8 D
           $member_input = new member_input($this->memberinfo['modelid']);  
: Y9 X' A! k+ {. o! P" W           $modelinfo = $member_input->get($_POST['info']);  
/ e' ~1 J, @. c1 w" o           $this->db->set_model($this->memberinfo['modelid']);  6 P/ g7 t* I; r6 X2 `9 O
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
+ R: J' A: ~+ C+ P           if(!empty($membermodelinfo)) {  $ F, O9 j& k; Z6 n- z, n
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ( o0 ^; J$ O0 H6 q% j. Y
           } else {  
! `* g" b( l5 V4 e. n              $modelinfo['userid'] = $this->memberinfo['userid'];  
* D5 f# _$ N3 x' ]              $this->db->insert($modelinfo);  
3 K1 V8 }: W5 c5 a4 c8 A. Y! I$ i" T           }   o% E$ d' p! R. v8 H; S% X# |. N
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,2 X2 n( `7 n$ S2 L
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
, ]9 ~3 B$ X0 p, H( w' C# T3 V- M8 _/ n& t4 q! ~2 C
8 J8 f" a1 g" s7 `3 f! `4 o5 k6 v

1 S1 n. j0 _# g- Q8 [. C7 I( s% gfunction get($data) {  
- _3 Q4 e( O8 h7 P) H1 U1 O/ L. C       $this->data = $data = trim_script($data);  
. z- u6 O  c  B! {  V- K$ D       $model_cache = getcache('member_model', 'commons');  
' F. O4 V8 d5 ^% Z& F% x       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  4 t& O* o+ o# d- m5 A! j
       $info = array();  
6 E. w1 C9 D! ]5 j% b. u8 n       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
$ x% q& x; _+ b% i4 U       if(is_array($data)) {  
% C' w$ j0 [& u0 U: j           foreach($data as $field=>$value) {  
4 c6 W4 z% v( V# M              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  9 a$ X5 q$ P% |+ w5 u
              $name = $this->fields[$field]['name'];  
* Q% z7 A; ~- |( _6 B( ^# T              $minlength = $this->fields[$field]['minlength'];  
$ q9 S$ E; Y3 H6 q* q4 [              $maxlength = $this->fields[$field]['maxlength'];  
7 u" }1 h& T# y, J% }/ C              $pattern = $this->fields[$field]['pattern'];  
; s; M) Z" V' Q9 i              $errortips = $this->fields[$field]['errortips'];  
/ M* K5 T7 R; H9 W+ \! ^              if(empty($errortips)) $errortips = "$name 不符合要求!";  ! b- q$ ^. o$ e/ r
              $length = empty($value) ? 0 : strlen($value);  . V, C+ T6 R& o( @( N7 \' a  G
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  - R( r4 n$ B" N; ^
              if($maxlength && $length > $maxlength && !$isimport) {  1 [& b  A6 q) N: b- C' f* U
                  showmessage("$name 不得超过 $maxlength 个字符!");  5 ]* d! E) K1 ^& D7 |
              } else {  
5 k/ I7 s' h' r8 q! L6 p                  str_cut($value, $maxlength);    K) @- B* ]$ e9 m: u/ }; a+ ^
              }  
0 B* o7 ?$ z, i' B5 x9 R              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  3 X- [( P# v+ R) l
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  3 [3 G$ H' w- V+ u0 }& l1 y
              $func = $this->fields[$field]['formtype'];  ( J' b# Y* `! E0 Z0 q
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  0 s- V" Q8 A1 _: X$ h: d7 K7 |" l( Z
              $info[$field] = $value;  
* ^! R9 Y0 B7 y8 S6 y. i& W0 ]- M- M           }  
/ `- S; F) K1 u( M2 I4 _  O       }  
" L4 R0 {* P+ K  [6 g- C4 \       return $info;  
, V* Q; z  n$ T$ ]1 j3 U3 @    }
' Z$ d$ d/ h0 x9 B/ Ztrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,7 F) }+ z$ e2 w  a

& _+ f) Z7 }, D; N9 B$ k- V% R再到phpcms\modules\member\index.php 文件account_manage_info函数
$ |* l, U1 n; b; z  u' B- n过了get()函数之后。) ]1 }5 z( ~+ T4 C; X6 ^
" G* }9 l% q4 r( g
# N9 M. i! Q3 f* `, T
$modelinfo = $member_input->get($_POST['info']);  
, n0 U2 C& O6 g3 ^+ G: u1 }           $this->db->set_model($this->memberinfo['modelid']);  
+ S+ U. A1 p, M/ c) ?+ E           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  8 N) l1 g9 y! Z
           if(!empty($membermodelinfo)) {  
! ^& k- @2 ~, L              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
4 w( B2 ?, u1 K4 b+ O& ?           } else {
3 j; u/ \3 n9 a. j. Q) ^5 R直接带入数据库,update函数我们跟进看看
% E2 s& |& `9 ]# H4 ~% |9 Q* [0 M3 V. N

* L& [4 h. I8 }* F3 v& d0 W" Zpublic function update($data, $table, $where = '') {  " Z) G! l0 [) e# L' W3 ^
       if($table == '' or $where == '') {  
# V5 K3 q) i0 t2 ~           return false;  
+ Z' @7 a1 k3 d: n& M+ D       }  
% ~( i& R# X2 V3 w' u       $where = ' WHERE '.$where;  
4 E1 H5 L; h4 Q( t7 \       $field = '';  % T6 ^& \' |- c
       if(is_string($data) && $data != '') {  2 x& C. M1 a8 Y8 A  P
           $field = $data;  9 n7 Q$ O# O' [5 A/ }
       } elseif (is_array($data) && count($data) > 0) {  
  p5 m2 A% ]: q" |  W7 c           $fields = array();  
' E  c4 d5 r5 O1 x/ Q           foreach($data as $k=>$v) {  
3 b6 z& ]6 [, d, r0 N1 F0 Y; G. F              switch (substr($v, 0, 2)) {  2 c% ]/ ^$ r. Q/ [9 K4 p" q
                  case '+=':  # H4 ~2 M& b6 R
                     $v = substr($v,2);  & G( ?# a# n/ E7 ~0 I# q) A0 Q& x# S
                     if (is_numeric($v)) {  / @5 J# y: o+ \8 C
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
9 E; F% b9 ^: ]) n: \: ]                     } else {  
6 b* N; h% E6 d/ G/ ]+ }" N                         continue;  
: l0 Q1 v0 w- K, k/ R                     }  - S/ N9 [0 k5 v( A. m9 j8 d
                     break;  1 Y  F. {% H$ }' d2 h* i! p( I% E. ?
                  case '-=':  ' f4 t1 B& p- V2 q3 x- c
                     $v = substr($v,2);  
* b. B* P, E  i, i+ B                     if (is_numeric($v)) {  9 m- w$ m* h& ~" U7 T& T
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ; P2 L4 J, L0 b/ T+ @  B- }7 b% s! e
                     } else {  + v3 e! E! Z! o  s, y
                         continue;  
4 k+ }  g1 `( g0 X; k                     }  & h) s  r- t( n2 |5 B
                     break;  % k/ y3 T# c! |% o/ G
                  default:  % u/ J, U- e, s6 P6 I4 P# C, Z
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
  d2 n! o; ^+ ^/ J( m1 i' [              }  * b. |6 i  d, }8 o! m* t% D
           }  
+ j( Q5 w3 R2 b* J" f: n           $field = implode(',', $fields);  
' `! ~5 H5 ~  a       } else {  
: Y. b) v7 p3 j           return false;  
0 N" p6 n7 v1 D       }  
9 J5 [  I8 Z0 t: O, Q       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  8 b9 q! L; M- M3 r6 s. B% q+ `. \: v
       print_r($sql);  
' q$ i) @% J( h       return $this->execute($sql);  
& }; v1 w1 ]5 E1 G& K3 R+ C    } + `4 h0 l3 s5 M8 [
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
& f, V( U' ~; G( F" Q' y
8 I3 G- z0 [$ P! a, N! O攻击测试:
* l+ E/ y0 X, @$ R6 X) i测试地址http://localhost, D+ g0 ^. w8 g' u/ O) q+ G
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
. f4 w) R6 N, Y" o: r' H5 }2 b1 u0 X& g8 p

, G+ _$ g' p3 p; Z6 w$ A) f" |
: F+ L6 s' ^+ R- n8 c
* Q8 z7 y; I( \4 B( o. ~4 X8 y, g5 _5 ^3 ^* U

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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