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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
! w! {( H2 [4 d1 S7 o  `3 G8 T) q漏洞作者:skysheep
0 D$ Y- E0 p: j; u分析作者:Seay% \5 \* `: ^( b
博客:http://www.cnseay.com/
' l) z( [. R8 H. |5 Q漏洞分析:
! m% Q# B9 T2 L, i6 ^& \  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
- E+ [6 {3 P- M' T% o% ^4 H
0 L) x. D" Z( G. D" K' q4 s- Y2 X, j" |1 \
% U, _7 G& H, O, i5 D
public function account_manage_info() {  
6 ~! Q3 U0 j' @: E4 X       if(isset($_POST['dosubmit'])) {  
# e% F" H( R. Q- i           //更新用户昵称  
/ f. [- Q, O( i3 _6 O. D8 |8 u' L7 I# C           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
0 L0 ^, G7 t" M+ G           if($nickname) {  
. o1 @0 Y$ @. ?- a2 Q3 p  A4 S7 f              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
, X! D! M$ J% g# p              if(!isset($cookietime)) {  
8 A  @. K9 c' ^6 T: t                  $get_cookietime = param::get_cookie('cookietime');  5 S0 E/ y' M; g) x
              }  # t* c, g) c$ ?! w, @( [1 B9 p
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
. j& U6 s0 u1 {" @              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  ; ~8 Q4 ]5 L; R
              param::set_cookie('_nickname', $nickname, $cookietime);  
8 R! B1 ^5 k' m4 c  p           }  3 j5 Y( L7 o& b
           require_once CACHE_MODEL_PATH.'member_input.class.php';  2 _- L* I/ g) B+ N
           require_once CACHE_MODEL_PATH.'member_update.class.php';  * @: k4 U5 O  d# T( E/ l8 S+ ~1 K
           $member_input = new member_input($this->memberinfo['modelid']);  2 W  ?/ h" F) a8 R2 O, v
           $modelinfo = $member_input->get($_POST['info']);  
; }' g, t" o% ]# ^           $this->db->set_model($this->memberinfo['modelid']);  
# d5 _% D+ F; `! q* _/ X           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
( @. V: K9 `! Z. _4 J           if(!empty($membermodelinfo)) {  
" w$ l: p0 j1 r              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  1 \- o* r% `  e3 C& z" X: _" x
           } else {  
' V, i  h0 j: ?6 z0 H              $modelinfo['userid'] = $this->memberinfo['userid'];  - D# k5 p: j! ?% K9 J/ I$ F
              $this->db->insert($modelinfo);  0 X/ j/ ^: s- ^7 ~, j4 \
           } % r1 X8 G, j: ~( E8 T! z
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
# M% W5 \- B  y4 [. r* U% ?- p9 E在\caches\caches_model\caches_data\ member_input.class.php 文件中:
. E. X6 a2 \; h3 O$ L/ @: ~. k; L5 n
) Z% q6 Y4 _+ z7 c$ z, g
5 P: [' F2 S9 R6 t
function get($data) {  ; _! ^3 U) d3 J. F" R
       $this->data = $data = trim_script($data);  
9 ~- s# D/ J0 J, j& ^       $model_cache = getcache('member_model', 'commons');  4 d8 p, q: B+ }( Y' ?
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  & j+ r/ _+ m& f. ]- n
       $info = array();  
5 ]1 G- b, G$ X+ v) G9 W0 x       $debar_filed = array('catid','title','style','thumb','status','islink','description');  # T" {4 ^+ z; F7 {. `
       if(is_array($data)) {  9 g9 I2 N1 e! H3 H: F& v; F
           foreach($data as $field=>$value) {  * e- X* d0 g/ S/ p: A3 X
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
1 a  A9 e/ `! |' O6 u& i              $name = $this->fields[$field]['name'];  4 `6 M- t8 o5 P& G
              $minlength = $this->fields[$field]['minlength'];  : r% B& o/ y( o9 B- Q/ v" {
              $maxlength = $this->fields[$field]['maxlength'];  
/ p( R: `% ^5 ?) b* x  K0 y4 p              $pattern = $this->fields[$field]['pattern'];  8 W+ ?! h; ~+ H0 R. k% G* B3 U0 i
              $errortips = $this->fields[$field]['errortips'];  $ j1 z; j' D$ d/ s
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
7 R# r" j* E6 z* {$ W: Q$ f              $length = empty($value) ? 0 : strlen($value);  # a2 D. M3 R% ?* s1 s( a9 Z2 t
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
; @% ~. [( N+ O, L( X              if($maxlength && $length > $maxlength && !$isimport) {  9 I' e" j0 K) P" m7 r
                  showmessage("$name 不得超过 $maxlength 个字符!");  
/ P) h9 C+ ^0 f7 s( G              } else {  
) X% \( W- t3 U                  str_cut($value, $maxlength);  
3 d2 g: J9 }: a2 ]( w              }  
3 f8 ~4 w- w5 _' o0 {" f              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  5 j1 z+ B/ [2 x: e7 x8 Q
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  " c7 H3 {2 Y( \9 G# r2 {2 \8 f
              $func = $this->fields[$field]['formtype'];  5 N6 g: n4 @  c% X* M. F
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
3 t# b& M, ?+ h1 d              $info[$field] = $value;  
% ]( `3 W- ?" I7 \& O! c# |           }  
' D/ m' @2 f. H% B8 E       }  7 F' u+ \9 _9 u
       return $info;  - L, C, a. K2 m- Y0 h
    }
7 E2 i/ `% s- y$ }trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
! S4 G. S0 C2 F! E/ i" U7 K: N6 J8 i3 X4 X- G
再到phpcms\modules\member\index.php 文件account_manage_info函数( `- T$ v/ t! [5 u7 e
过了get()函数之后。, w# o4 a/ [8 u9 _' D1 n

$ I2 M* d+ l9 Z, Q% g. p
  H  {5 U/ Y$ Y& ~; Y8 S2 I$modelinfo = $member_input->get($_POST['info']);  
" k" t) B+ O- K; ~& @3 v           $this->db->set_model($this->memberinfo['modelid']);  
5 Z7 W6 n3 F  B' f8 F. L           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ) a3 a+ i1 \% R' }& E3 Z
           if(!empty($membermodelinfo)) {  9 \* r: N8 M$ `* F4 c
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  3 ?, j+ F) m- D+ M* @' L
           } else {
% X/ Z! P/ X. R' N( U$ I+ A直接带入数据库,update函数我们跟进看看
8 y( F: g1 y# W# B/ Q8 o. w; j% ?# C: ^# R# z8 R
: C* d; i2 ~  ~2 Y" f1 P4 X9 Y
public function update($data, $table, $where = '') {  1 r: z. U; d  R, ?4 \' z3 a, i
       if($table == '' or $where == '') {  
* C- v2 M7 m3 M. f2 J6 x2 h           return false;  
- b) Z1 Q* v: \; e' h       }  . w+ ]9 S$ W% ?
       $where = ' WHERE '.$where;  $ S$ J- ^3 Q( w5 a
       $field = '';  
7 R8 f0 K, p0 v       if(is_string($data) && $data != '') {  / T" {8 P8 ?" P" K
           $field = $data;  & \8 A% u, u; ~
       } elseif (is_array($data) && count($data) > 0) {  
0 G& M: j8 i) H1 @           $fields = array();  
6 Q' |* `; s  e( W1 I           foreach($data as $k=>$v) {  3 p0 m/ i! B/ {* D4 X8 W
              switch (substr($v, 0, 2)) {  
& V  _9 R( M- `3 X; s/ a* N                  case '+=':  2 o. A% Z/ H. X: b% A  P) {' K0 o7 c
                     $v = substr($v,2);  # }9 Q# Z  F/ P: E7 Z$ b0 u3 L
                     if (is_numeric($v)) {  
, D' H, Y% j  e" j- p1 m                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
' f" W2 |6 B3 F8 ]                     } else {  
" n0 y5 n8 [- R$ r                         continue;  $ ?7 b0 {1 N3 V2 `. E$ j- [
                     }  / o( B7 O+ j9 q0 c
                     break;  . K9 W5 f; h; _( {& V/ M9 z
                  case '-=':  " e( _6 o* v$ r( j) V  ~
                     $v = substr($v,2);  * b& j* _: ]0 l5 `. A+ w) U  j
                     if (is_numeric($v)) {  0 ~7 g' J/ W# `- e; M' A
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  7 _: ]1 L5 p1 J/ k! N. C. D
                     } else {  
5 v$ D6 ]4 b4 _. J                         continue;  
6 s7 C3 e$ [6 @  |                     }  3 e; p- w" ^8 v* H' N9 M
                     break;  
! t; J% ~% L9 u4 q                  default:  1 E8 e9 V( M% q3 l. V" {
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
$ }; v  ]0 H9 i% ^" |, u3 j+ `              }  
# S5 }; n; w; F) Y0 Z           }  + T1 v, ^2 |/ R
           $field = implode(',', $fields);  4 r$ ?; h/ K( ?# v; p4 m) n
       } else {  
" U! ^2 y) `0 i7 ^7 n1 }           return false;  
& Y7 |" p3 L* U" R8 ]       }  3 O1 m2 ^! V) |7 O# `( C+ R
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
  R" ?0 s9 p4 ?% X& q       print_r($sql);  
- X/ O. n$ r. r8 B5 _7 J       return $this->execute($sql);  
: @) S3 \6 T$ N    } ( q# M, p% }) S- l) Y' [+ H
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。% z5 E  W7 j( q: {3 ~  ~
( }0 t4 A4 l/ N7 x, F
攻击测试:; B; o3 N+ d; a" Y! e# p
测试地址http://localhost# e. n  k0 O. t% _: R6 w
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句3 s. F7 `/ M* G2 o0 {, [) x4 Y

" V& }1 D  T& y" a; U * m: C: |" O  `9 |' D9 Q

  M, Z/ x8 h8 t4 V
# d& }3 F# o  }8 k: w3 c/ s* N6 I6 y3 T" s2 O( @; X  m

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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