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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告' v' w5 }% y; [' T  r. U
漏洞作者:skysheep
5 ~' s9 C/ k0 v' Q% l2 x分析作者:Seay9 y, q3 _) P: R( G
博客:http://www.cnseay.com/
( ]+ V' h3 _, l6 K, S0 \. j漏洞分析:
7 P+ X) L$ b+ l8 {* m  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
% R4 O& d8 A0 Z5 Z. O! H2 y2 U! t; I0 X; }7 K- o2 r  p
$ y; S4 i) }, \: H

' ?5 p2 E" X3 M, p' H% [public function account_manage_info() {  
7 Y5 C0 p* v9 |2 q2 X( a+ T       if(isset($_POST['dosubmit'])) {  ! j0 D- y( Q; p, v& p
           //更新用户昵称  
- `" |2 X2 W3 q- B           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  2 F* a7 S" |6 C; F1 m8 B
           if($nickname) {  - d' a! U5 r2 p7 v
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  / j: v/ I! D7 ]4 b" _7 f
              if(!isset($cookietime)) {  ' D& _4 U$ Q0 Y( B% W
                  $get_cookietime = param::get_cookie('cookietime');  4 w3 _: `: _" @: `: F) G
              }  ! }0 w" `0 }9 n4 w" ^# Z
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  ) _1 L' s8 X/ I  ?7 _/ J
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  4 y) Y( l2 k0 G3 @  o3 X
              param::set_cookie('_nickname', $nickname, $cookietime);  
$ e4 G5 U- U: B! s% M! t7 ~1 B9 B           }  7 @( {* J! s* c3 M8 b' s4 E+ s! X
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
! c7 P' R" g' ]2 G: M           require_once CACHE_MODEL_PATH.'member_update.class.php';  , S8 K# j% u" [% K" G
           $member_input = new member_input($this->memberinfo['modelid']);  
# o& M( m3 I( L% d! _           $modelinfo = $member_input->get($_POST['info']);  
/ ]7 o( ?/ F  Q* @" K; I           $this->db->set_model($this->memberinfo['modelid']);  % p/ J% C1 e8 _
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
8 |  Y' G8 @( K% Z0 e           if(!empty($membermodelinfo)) {  2 C7 W. O' p3 a: @  D
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  1 N+ f; N5 X; f" ^  a4 k
           } else {  1 B- e6 M% u' `4 j& o; @
              $modelinfo['userid'] = $this->memberinfo['userid'];  
& o  d: B) ^1 F# a              $this->db->insert($modelinfo);  8 N9 ]" K9 V: C! i2 G/ S. ?9 E% T, n
           }
! F$ F5 M* o. [2 h% I2 x; L代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,5 v; p7 x9 g/ l" R# k; D: v5 P: C$ m
在\caches\caches_model\caches_data\ member_input.class.php 文件中:" r! n9 a# t& j) l. l" q
) ^$ L& H" W/ }! c! Q1 ~" ^
7 Z2 f( G; r6 L" O6 D8 l1 Z4 i6 ^
+ T2 a5 w+ r: z( F7 m! s
function get($data) {  
+ i, {0 a$ k1 I9 m: Y7 m$ L; W1 N       $this->data = $data = trim_script($data);  " {- I/ D, ]% W, ^' `+ g
       $model_cache = getcache('member_model', 'commons');  
8 R# V+ t# g1 _* T2 G; z! o       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  * g. `# C9 h2 Z  s: @5 y8 \
       $info = array();  ; R' ^: u3 }# D; r( H( v! Q
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ; {2 W5 B1 u/ u# Z% y$ @
       if(is_array($data)) {  
( j( a% X% L% E  T6 T           foreach($data as $field=>$value) {  " H' Y; ^) U7 D: t6 {
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
& S6 ]! Y8 a0 y, _; o              $name = $this->fields[$field]['name'];  
$ V+ V  a8 ^* C: k' v: g" a              $minlength = $this->fields[$field]['minlength'];  4 Q" o5 J( F1 R; T
              $maxlength = $this->fields[$field]['maxlength'];  & T% B; @! Z7 G: h0 {6 @: Z
              $pattern = $this->fields[$field]['pattern'];  & F# I/ ]3 H+ x$ z
              $errortips = $this->fields[$field]['errortips'];  & q) `' q3 d' N. R/ l  r5 u
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
8 V, f! D; ]# V6 P9 r              $length = empty($value) ? 0 : strlen($value);  
( D. @. b) ^+ l              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
; _9 j+ H7 j& i) Z              if($maxlength && $length > $maxlength && !$isimport) {  * @1 e. F# P) B
                  showmessage("$name 不得超过 $maxlength 个字符!");  7 }$ n1 G$ D+ c7 f* b3 Z# e
              } else {  
! Y- _; Q0 I% K2 S1 v: q                  str_cut($value, $maxlength);  
' c* L4 J( @/ O$ m, F/ c+ e8 X% |              }  
4 A# t" O* s5 q8 b5 v3 U  @              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  2 x7 ?4 D: c" A2 Z; w$ c! \: O
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  " [3 Q0 u4 T" c& R8 ^; Q6 L
              $func = $this->fields[$field]['formtype'];  ; K- m1 g- E8 c5 h3 F' K5 ~
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  2 D5 h+ q" Q2 m; l% N
              $info[$field] = $value;  
5 f: s7 {! y& e7 \8 M           }  
' b, m/ F' b  J! P       }  
8 ?# \. j' M; |+ ^0 Y/ C2 r       return $info;  . B. X- |2 z1 q9 P7 |$ b
    } / r3 C: C; w- v$ D% n7 B
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
! B' I7 N/ {8 N) x! N' h4 D1 l5 B! ~
再到phpcms\modules\member\index.php 文件account_manage_info函数
) n5 A5 x7 p( W% S6 E过了get()函数之后。5 Y1 \3 d3 }2 G( D; ~

0 x1 l6 H7 N4 v+ y! c
% w( f* K- x$ h, K$ @  c( O$modelinfo = $member_input->get($_POST['info']);  % G  |$ T/ M& i2 ^  U- S) u7 f
           $this->db->set_model($this->memberinfo['modelid']);  7 F3 I0 S3 H3 M1 r
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
/ i6 o7 w/ X& c  S, p           if(!empty($membermodelinfo)) {  
$ o3 Z2 g- h9 _. w5 n              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
3 E$ L6 u; Y4 e9 p$ a$ `           } else { 6 ?7 W, `7 u/ [1 L2 n
直接带入数据库,update函数我们跟进看看+ w3 L0 C, E* ]6 G- V
+ Y! C, C& u. ~! U4 O2 X

0 {" t. H; }5 Y! `8 xpublic function update($data, $table, $where = '') {  
/ K, W. ^2 u1 E* D* C: f       if($table == '' or $where == '') {  * X5 o  l+ q8 B! c
           return false;  7 {+ R6 l; w6 ^- a) s4 w2 {9 b, J0 Z
       }  
) z- l8 Q# {5 M3 U       $where = ' WHERE '.$where;  
. t2 Q+ k2 n  ]9 c" y7 z! ]       $field = '';  
6 ^# q1 _4 g* H& R1 P3 B* T/ ^       if(is_string($data) && $data != '') {    Y( @2 x* X" x9 w7 E; e. p. ?
           $field = $data;  
  j0 O1 A+ }9 N/ R5 f       } elseif (is_array($data) && count($data) > 0) {  
. x1 P$ ^9 V, X           $fields = array();  $ `6 R5 A1 ?# Y& Y2 W# ?/ \9 S
           foreach($data as $k=>$v) {  
# ^7 |/ b7 K3 e2 J) j7 w              switch (substr($v, 0, 2)) {  * R* W+ g& y# n1 H
                  case '+=':  ! H) @& {) n& ~1 v
                     $v = substr($v,2);  ! S  U4 ]! G) i5 i$ J; f7 ]
                     if (is_numeric($v)) {  ' ~, S8 c9 E: i4 Q
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
/ P: E6 R% f5 s2 v% _- K                     } else {  
* @! O3 x7 r) `0 T" ], A                         continue;  8 {+ P; I8 E9 _1 l" k9 f/ b" W0 o
                     }  . X- K, u7 q" R) j8 s
                     break;  
$ @4 `1 z2 E( Z' d$ t- a- V6 p& X: T                  case '-=':  
" b: C& F1 |" w$ K$ u                     $v = substr($v,2);  - E1 j! n- m8 i& m6 A& `0 N) V" S  ^
                     if (is_numeric($v)) {  
7 z* p) ^! x( X& E9 D; C5 T, {                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
* e+ W- F% ]7 V5 G2 n: T                     } else {  # _8 I2 K  X4 e
                         continue;  7 j0 a4 p* a( I  U1 ^' O8 s# [! I
                     }  
3 C* f1 _& S( _% ?- }6 ]3 z                     break;  
) |) n. k7 `3 S# [                  default:  
6 q& V; z! ^! A% m: Y5 d( x                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  * w4 ^* z) o; W: {( Z
              }  
  Q3 f4 O# O( u6 P/ Q6 x) k           }  
" O; i' K5 k) t* X! z+ T+ _- Q$ C           $field = implode(',', $fields);  
) I. X! i4 L3 V' K       } else {  
5 V. s& f. [$ [1 M           return false;  
8 C5 a" }4 U: @% ]" j: Y& u! L       }  , @; ?! T" v) u2 F
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
3 P2 K+ R2 ^" Q9 ~       print_r($sql);  : }& I. \4 L, y- E+ o1 f* r/ Y
       return $this->execute($sql);  * p4 }1 S/ N6 e0 t
    }
; ?5 v4 K# B+ Z+ q从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
4 L, c. m& _5 k) O( `6 s! C1 P" v  |) V/ W0 T, v) T4 N7 m1 m
攻击测试:
2 f$ q( y! w6 Y0 v测试地址http://localhost5 f9 M; F, N# y# z2 n
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
7 A4 D) V( ~, a0 s! r# P7 b
/ b9 l7 y' a: {! W8 Z; F+ U / t. k2 M5 C7 L. J& }  ^8 }
% t% y8 e# d9 V. ?

! Y3 R, v8 c9 |2 [- |  T/ r2 f6 ]' J& m4 Y2 C5 j

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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