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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
! w% m% R9 m1 k3 Y& A9 |5 u7 ?) i. z漏洞作者:skysheep- ^2 H  W' ~# ^' ]/ ^
分析作者:Seay
0 p$ x2 u: }! A2 s. v0 |博客:http://www.cnseay.com/2 O7 Y$ u. ?/ H6 ]' Y
漏洞分析:
9 S* @) u: q. b) j+ @  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
8 ~5 i6 a) G/ _
# y+ z& s' O. P9 g6 |  u( G  I
- G' }, ?! v4 V6 R & S; |. {+ R! ^8 L& E. ^9 O% `8 t
public function account_manage_info() {  
6 s" Q# r* s0 D       if(isset($_POST['dosubmit'])) {  0 v( e- ~: E+ m  j) u7 S2 R
           //更新用户昵称  8 X8 B2 |) X' F3 K" }: w! k
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
0 E$ {) d& L# J, V+ A) y! o' y1 v           if($nickname) {  
# X9 @3 A' k% s( h6 Y* j              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ) y* V; I+ ]: k1 v" K6 L
              if(!isset($cookietime)) {  , e/ E$ s  C3 ~! S" t+ ]8 C2 i0 `
                  $get_cookietime = param::get_cookie('cookietime');  
5 A3 k+ n4 e$ a  T& }' e              }  
2 P; u4 @3 x, j2 o, T! ~              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  + R* W+ j( o0 l" G
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  " t4 f8 Q% D4 S8 y/ T
              param::set_cookie('_nickname', $nickname, $cookietime);  
. c+ {" Q$ H# o6 ^/ I" \           }  
) w1 t: G$ R4 b' k1 V! G) S           require_once CACHE_MODEL_PATH.'member_input.class.php';  ) z0 F4 y! I7 j% Z
           require_once CACHE_MODEL_PATH.'member_update.class.php';  0 r$ r; ~5 \: [" A# l) T
           $member_input = new member_input($this->memberinfo['modelid']);  
! ^; y& ]! x: Y           $modelinfo = $member_input->get($_POST['info']);  # X; V. f) z, v3 u* q
           $this->db->set_model($this->memberinfo['modelid']);  
8 [- [8 i3 S/ }! C! |/ w           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
, `# X) P, X8 D. L: h           if(!empty($membermodelinfo)) {  1 U: L) I3 d6 ]0 ~9 x( e, |
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
% r! X3 [0 v+ ], ~7 E3 k. {# r; \           } else {  ' n" K) ^6 s* b) }% A6 v( z; c
              $modelinfo['userid'] = $this->memberinfo['userid'];  
5 `0 K0 Y0 L$ l4 Q- {& K3 G' T              $this->db->insert($modelinfo);  - Z: Z6 x9 T* e! r! _) F
           }
* @% V# H$ Y: {6 E  E代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,. r' K' G' q: M% {; O
在\caches\caches_model\caches_data\ member_input.class.php 文件中:" o  R+ d: x" {
& h! s# |' r: C4 O5 ^

4 O# l! J# @8 T$ |) k # w" a& Y9 u$ ~7 W0 d. s7 L% e
function get($data) {  
+ u0 ^2 ^: b( n       $this->data = $data = trim_script($data);  : q- _; `% J6 q. L. u/ O( j. S
       $model_cache = getcache('member_model', 'commons');  1 J5 w  t+ i; D8 _! s
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  : Y* e2 R6 O& g
       $info = array();  
9 q# c6 ]4 R% [. `       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
% w$ O% ]! m+ m% I4 ^       if(is_array($data)) {  
* a  o6 V" q  o7 t           foreach($data as $field=>$value) {  5 B& {9 g" F. i- R0 r
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  7 d. a* j6 I6 m; f- d) W
              $name = $this->fields[$field]['name'];  ! F) d. l$ ]! ?" K7 i5 _
              $minlength = $this->fields[$field]['minlength'];  
# _* l: j' ^  _              $maxlength = $this->fields[$field]['maxlength'];  ; o- q2 b  i* y' @* Q
              $pattern = $this->fields[$field]['pattern'];  2 K! s2 c) ^3 `3 q* H/ ?
              $errortips = $this->fields[$field]['errortips'];  + v; I7 |# F& M; ^; j, H
              if(empty($errortips)) $errortips = "$name 不符合要求!";  0 L# b3 [( i0 Z7 _
              $length = empty($value) ? 0 : strlen($value);  & `6 P; r9 P7 l8 |2 u7 k
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ( ^( W( X! S7 Y) N6 v
              if($maxlength && $length > $maxlength && !$isimport) {  
( D- Z6 O/ F( n/ z0 b- `6 ~& \                  showmessage("$name 不得超过 $maxlength 个字符!");  
, J" S8 d( Y6 z% J5 j) y$ X" S              } else {  
  c7 P3 I" n1 @+ J' U                  str_cut($value, $maxlength);  
: v+ j! y! x2 `# O! o! h! z              }  
- j- q  {  [3 v, h. V              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
2 D2 }+ J" w( |* R                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  / j& {! T. }" [' H
              $func = $this->fields[$field]['formtype'];  0 u+ {$ x* m4 P1 B( R
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  6 n8 U) E* B2 h; p( ^* z
              $info[$field] = $value;  ) e1 l- |3 p! u0 z9 \) C
           }  . W8 _, [! g( v+ _0 |
       }  
0 k# `4 c1 u9 P; |* e$ d4 G" D       return $info;  * U; m' P; ]7 I! @( p# e% ^
    }
( L0 b  c: c( V; |; H& m  H; T4 s# Etrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
9 `& D' s% Z6 S6 I5 Z. a: ?! m* S: m6 X% O
再到phpcms\modules\member\index.php 文件account_manage_info函数# X; B6 q" O1 b$ G6 n
过了get()函数之后。
$ ^' y; M" A0 @' j6 R3 |2 l# B+ T" c# [. p. L
6 V3 L: J% b% x' D
$modelinfo = $member_input->get($_POST['info']);  7 B% b8 o2 f. D( K$ q* C
           $this->db->set_model($this->memberinfo['modelid']);  
0 @; i8 p, |2 K           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
4 S* [2 }) `) C& A- w- k           if(!empty($membermodelinfo)) {  
, o" c7 R. P1 g9 k0 u3 I              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
0 b5 Y1 o% X. ]+ K9 b: i           } else { , I& e+ _& Y# B, o/ D
直接带入数据库,update函数我们跟进看看9 `' X0 d; P1 [" B2 V

; v" w, T# G9 ]& v! q6 V 7 _% u' o% x: k- T$ ^7 a7 F5 R
public function update($data, $table, $where = '') {  $ `0 l5 M) ?* G+ W& ]; v  g
       if($table == '' or $where == '') {  " Z6 }3 D2 I' R7 L% Z2 ]: v
           return false;  ) l% R' R) g* m0 W+ r% e, y
       }  + U* |! K0 _. y1 L6 r% O  b) I
       $where = ' WHERE '.$where;  
- A# m% g" T5 |: a4 J       $field = '';  
; O, B- T' a. n/ w" N       if(is_string($data) && $data != '') {  
+ i( y9 ^% j7 C9 |           $field = $data;  - L6 i! d6 ~" |) ~8 x
       } elseif (is_array($data) && count($data) > 0) {  2 e# ?( {. D2 v2 F
           $fields = array();  
/ a$ J, U% h( y3 F           foreach($data as $k=>$v) {  4 D- q: ?1 P. w. U4 `7 e& k3 ^
              switch (substr($v, 0, 2)) {  
5 E+ W* P! t( N/ ]/ p                  case '+=':  1 Z4 p' n" Q* m
                     $v = substr($v,2);  
2 t3 @0 ^, S- G1 _9 ^                     if (is_numeric($v)) {  4 _" y- F: G/ A
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
2 a* R: v  f) c7 f) h- B+ J                     } else {  6 ?7 ~- J- D8 g- d% Q
                         continue;  9 J/ l: ~9 f' H: k
                     }  
- e7 ~4 S3 M0 v3 |. }" p                     break;  ; Y! M+ b  W, T6 ]
                  case '-=':  
& n  b& j; l7 P( T' S, ~6 `, n                     $v = substr($v,2);  , g  G  J8 G* }( B  i
                     if (is_numeric($v)) {  
0 D# B& t8 d! }: {. N& f                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  : {# w* p. }6 e& n! o( w6 Q( |
                     } else {  
% @) p+ N, Q3 K% R2 m                         continue;  
6 J/ b) ~/ x3 F                     }  
: g- z  s4 r5 W1 z5 F' R6 p) A                     break;  
5 l, K; }% r4 L                  default:  
" _+ r% F+ O6 |2 e- {. _4 r- Q                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  & H1 n! O% p+ v- l
              }  
1 S5 h6 m3 x. L  D0 y; b           }  ; z4 n& I$ S1 A+ J& e  q
           $field = implode(',', $fields);  
4 C+ ^0 C. V! z, d1 Q3 x  _0 l       } else {  + X' w1 m; C4 `5 ?( G1 E2 s  d
           return false;  
; r/ Q9 B5 `  F  ]- {- n       }  
1 _3 l: L9 ]% k0 N! o       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  2 q( C6 ?  a' k. y
       print_r($sql);  
( r5 N2 ?' ~# ^6 e" J; Q% J/ H" k       return $this->execute($sql);  
' g, M4 h3 y4 G! @    } % R5 ~0 K' S  s( V6 z
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ [+ B+ C$ _% ~: ]; D! H- N" k* ?: D, f- M. `7 h& E7 K2 e! |6 Y9 g
攻击测试:
/ f0 Q8 r. y+ g测试地址http://localhost
. U6 T' E9 S6 U/ e, Z4 R  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
/ ?5 ~/ E" z; g
0 H' ]# a; F& f+ d! F: M- L6 u / W* F) d4 x8 t- p4 ?; {

2 [7 l- h2 w+ ]/ a* p  y+ ]/ e" @! r! T8 _; H- i

1 j) S2 Z# b2 {* }# u

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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