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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告! \3 b( [* k" G8 N
漏洞作者:skysheep- B  w+ o1 b' {: L7 N6 p
分析作者:Seay
) q% X3 l! z$ R* @% [7 H4 T, w博客:http://www.cnseay.com/
9 f& |! [" `! T* |( Z. @0 x漏洞分析:
( ?& w0 a0 |7 e/ [& Y0 ?' L! k  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。8 |+ m/ M2 M& B( w# E0 }  X
% J! _+ D) I9 n8 C& ]/ h0 |) B
# S5 I1 F. p) g. c# f/ i3 z: I' l

4 J9 k; O$ C* Qpublic function account_manage_info() {  
! B+ A4 K) z" m5 X" s, H       if(isset($_POST['dosubmit'])) {  5 L% @7 d8 m+ c3 |3 y/ n/ W
           //更新用户昵称  9 V1 w$ N, D+ R9 U2 \) T
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
2 [( z% @" N$ P' B; O& v           if($nickname) {  
9 a, K2 n% J7 w, s; ?) J              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
) i0 s- z) y; e4 k/ c) p              if(!isset($cookietime)) {  
3 T2 y1 I5 \0 {8 y  X$ h/ G# A' ]                  $get_cookietime = param::get_cookie('cookietime');  
( [9 \0 t' ?9 s- `3 j$ Z. ]; C& Q              }  : w8 u0 x) i( n
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
1 q2 F% ?$ C, {$ V2 W1 J8 x              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
* ^3 E7 }3 ]7 D5 F& S  Z" V8 {  h              param::set_cookie('_nickname', $nickname, $cookietime);  
0 O9 H) y% Q8 i& g( R0 t! ]           }  7 @7 Q3 Z+ M. |# X. Y, ]2 Y
           require_once CACHE_MODEL_PATH.'member_input.class.php';  3 L& I& |1 d& w3 a
           require_once CACHE_MODEL_PATH.'member_update.class.php';  ) f/ q) d- [$ ]" _
           $member_input = new member_input($this->memberinfo['modelid']);  + G1 k4 a# D- q5 g' T2 s" J
           $modelinfo = $member_input->get($_POST['info']);  
% y" J* d" z, I' E# D+ @1 A           $this->db->set_model($this->memberinfo['modelid']);  ' k, j9 E" d/ j8 i* E3 L. d2 o
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
3 ]$ E% ?6 O0 ?# s/ F# u           if(!empty($membermodelinfo)) {  3 P, l5 o* s' U- \1 x7 {
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
7 d# ]: G0 z- k2 f8 V8 g           } else {  ; F( a8 C: n) ?
              $modelinfo['userid'] = $this->memberinfo['userid'];  ! E- R8 X" H6 Y# w
              $this->db->insert($modelinfo);  $ u* E; g2 y/ M* G# v5 z
           }
# I2 o/ j8 [& O7 I$ e" f3 e5 Z代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
  u, V/ S0 I$ R5 n3 p2 m% }在\caches\caches_model\caches_data\ member_input.class.php 文件中:
. S! U" m# J3 ]+ p( q6 j! W, [$ s9 B9 A4 `$ y7 ]( W- G' K

( D; T9 l* r7 }) j + N+ O% k4 L0 S$ e: a9 C
function get($data) {  
6 ~3 W$ W- N) x- c/ h       $this->data = $data = trim_script($data);  
1 o: ]9 ]8 t$ L9 q       $model_cache = getcache('member_model', 'commons');  
+ s7 c5 g' C- A+ q# {  ~, }       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  : q- g5 e  Q3 }- R1 l) A8 Z: t
       $info = array();  
6 M) l3 J* t; m3 O/ g) g       $debar_filed = array('catid','title','style','thumb','status','islink','description');  * V; }# F* x0 B: y8 y5 x
       if(is_array($data)) {  
4 ]0 w+ S: i5 E9 j" V           foreach($data as $field=>$value) {  
/ Z8 m. b" f% v' D              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;    x+ i. O2 @# l2 P
              $name = $this->fields[$field]['name'];  : a  i& B; P# [! r9 s+ K* o  `
              $minlength = $this->fields[$field]['minlength'];  * p; D( i; b. {, n+ M
              $maxlength = $this->fields[$field]['maxlength'];  
2 }& s4 @2 }* O( l$ d& N0 ]              $pattern = $this->fields[$field]['pattern'];  
( g5 N# i2 d, h! l, \$ o              $errortips = $this->fields[$field]['errortips'];  % i- \4 Y! z3 @' i: S% |
              if(empty($errortips)) $errortips = "$name 不符合要求!";  3 N- Q2 `9 H" Y/ T
              $length = empty($value) ? 0 : strlen($value);  
  a2 {; w1 p0 c2 u/ [              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  1 q( p9 _- x, L3 k
              if($maxlength && $length > $maxlength && !$isimport) {  3 @2 `! W% t  m
                  showmessage("$name 不得超过 $maxlength 个字符!");  5 }  ?2 b5 X* Q  Y3 q( S2 I8 A
              } else {  
$ n9 b- S0 v9 O3 R0 A2 W                  str_cut($value, $maxlength);  
- ~- P) E3 ]7 F6 ^/ T, l5 C              }  / }0 @  f5 j, Y+ A% L# P
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ) u* V! ]! \6 S* Y
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  / C$ @4 I7 l# j2 ~1 L) |
              $func = $this->fields[$field]['formtype'];  
, }" e3 y5 a& V0 m! `/ A! V              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ' g5 K+ R5 u9 j/ p% p  g, `
              $info[$field] = $value;  
) q6 `/ Q$ C, N/ o+ F           }  
3 N7 X9 }0 D0 S& _3 H: u       }  + b. ~& V5 {8 W1 C7 u+ j4 u! M$ p
       return $info;  
+ c" m0 {) W7 j; I% o    }
6 w/ |, c' `. m5 ?9 W6 O5 itrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,) Y) _/ a/ \/ B2 D* e9 s

; d- x- D5 d) u7 U5 G  \再到phpcms\modules\member\index.php 文件account_manage_info函数' v0 |, d8 T, T4 R& b% L5 K
过了get()函数之后。
; O! N* R! ^$ A) k, n1 R
: I: S; ]' V; n8 I
1 W# O0 Q4 S$ R2 K( w$modelinfo = $member_input->get($_POST['info']);  - H. s5 G2 d6 `( J
           $this->db->set_model($this->memberinfo['modelid']);  
6 E% X* X. h" j" n0 S5 z: V           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
6 S* E" U0 h4 C3 ?8 I; l! @: k" _           if(!empty($membermodelinfo)) {  
( r( f) a6 O% t3 K, X: `; o, \, n: }              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  - q5 C6 s0 R& \
           } else { 7 C( V5 b, Y, b0 y' T4 e
直接带入数据库,update函数我们跟进看看
0 h) y$ |2 j' T3 h/ A: F: ~; H$ `# V& m6 f7 Y* w
! b8 D, l1 M. u
public function update($data, $table, $where = '') {  
+ o3 z( a( s* B" z; ]       if($table == '' or $where == '') {  7 s- X- G. i, W9 R. h
           return false;  , x- ^! l8 Z4 h
       }  ; U+ ]4 J' c2 \* j$ M8 f& u0 w
       $where = ' WHERE '.$where;  
  n3 Z. R  G7 r       $field = '';  
) Q6 t/ B1 c3 b2 j: _       if(is_string($data) && $data != '') {  $ ]$ I3 J. J# _( [
           $field = $data;  
$ F2 o7 z: c9 w( M3 A, s  V( i6 b' ?       } elseif (is_array($data) && count($data) > 0) {  & t6 {* _- B! c2 e1 t0 y3 T2 v7 Y
           $fields = array();  
$ l0 b; Q" v* U           foreach($data as $k=>$v) {  
1 [. t2 t6 ^0 F  R+ p9 N              switch (substr($v, 0, 2)) {  
4 i% j# M- |/ C7 x. g" i  C                  case '+=':  
# j/ K! i5 T0 F1 S7 T" {/ `3 z                     $v = substr($v,2);  
- M( V9 p3 V; j/ R                     if (is_numeric($v)) {  % h5 ~3 {' z$ G4 q+ m: V
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  + v% q. T2 k; t- ~4 p* K7 Z+ H
                     } else {  7 W" y/ _% m! {1 v
                         continue;  ; }3 t9 t$ u4 `9 P
                     }  
" m1 }8 P# j. P; C; E4 \# w                     break;  
. b" r( ~/ i/ G8 [                  case '-=':  * \3 S9 g7 ^& |# X4 x9 j
                     $v = substr($v,2);  # p+ r  x2 g+ A* e% _
                     if (is_numeric($v)) {  
  B0 a- P0 T; U+ C& n( Z) i: V: Y                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  . c& U" n) d' p6 Z. o$ {
                     } else {  * a: w( b) ~6 c8 e- v& A" S
                         continue;  2 M( T: `- ^4 y- E; ^; }' c2 x3 d
                     }  + _, O% F4 r2 O- F4 }
                     break;  
/ A0 S* ^. g& G: j' A9 q3 X* S                  default:  & v# }7 q2 G& a5 f+ v* v
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  0 Z, H. i! b) ?& N6 K9 t- U' C, ]  @
              }  
; `0 A: q: P2 @/ k( i; O5 [           }  
: S6 y7 _' F; r) a7 C           $field = implode(',', $fields);  
' B$ o& \5 o9 [3 D$ L       } else {  % B6 |) E4 h6 k# F0 L, W+ {6 f- N
           return false;  
; E4 H: t" g( [3 r9 Y       }  
. C4 _9 H/ i' x* w& a) R       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  2 h6 Q6 P' T2 @4 H9 s* }" j
       print_r($sql);    U1 u  t" @6 z! O
       return $this->execute($sql);  
5 _2 N! j6 k2 F' h    }
  U, @( L8 O8 @从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
9 }) Y8 P4 g, z
+ Z$ P* U0 O1 b4 U7 Q- c7 D攻击测试:
. G5 E/ I$ w$ D/ C- y6 n' j测试地址http://localhost
. b  E5 U1 i6 h) a: S  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句# ~  J6 P* a" [) C  I
* ~0 K, I# d) _

; Q6 Q% B4 D3 a4 e! k: c0 }* ~! ~2 h1 ^, S% K6 d6 _2 ^: V
! J; |8 e% I% i

. q" S6 P  y3 d  F) {4 W: |

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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