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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告5 J: z& \7 k. m  A* ]' ^, ~
漏洞作者:skysheep
+ Q5 G/ `. C& a7 O( W: `9 W分析作者:Seay* [( X9 |4 u" y4 z2 d: K. H( Q7 m
博客:http://www.cnseay.com/
: F" T: Z; o3 d2 A# E漏洞分析:
) o7 L- [4 X7 a  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。& y, i' U6 j. M- {5 z
" j. n% @$ b" @: i! R) b  E

3 E6 x! h- a, I3 h" l, ~7 Y8 N
: g1 S) I( R4 B7 B* apublic function account_manage_info() {  
% ^; D! w1 {& M7 T$ e" O' Z       if(isset($_POST['dosubmit'])) {  . J% \8 E' b/ ~1 Y0 u
           //更新用户昵称  : z9 ?+ ?6 R2 a4 q) j. r; x! U5 ^
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
" y# C6 {, M6 }6 a% a' e3 ^8 ]           if($nickname) {    M! [3 L% ]3 a1 `- m" r$ W
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ' H% b1 M' f5 s9 V- d, x; F
              if(!isset($cookietime)) {  
% P( v. G* y5 q0 S                  $get_cookietime = param::get_cookie('cookietime');  / L( x2 T+ i) X+ I0 b
              }  1 t+ V7 p: w0 }1 ?5 E
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  0 |9 C; `# n% i" x
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
9 _+ t/ T. U9 b7 {( l; M6 o              param::set_cookie('_nickname', $nickname, $cookietime);  
" a7 J8 `; H8 m6 l8 `           }  
$ W& g6 E6 Y- {" T           require_once CACHE_MODEL_PATH.'member_input.class.php';  
; C& b5 x- N/ b: y6 p0 N           require_once CACHE_MODEL_PATH.'member_update.class.php';  
8 g5 O* E1 ^0 L7 c8 K5 |: x           $member_input = new member_input($this->memberinfo['modelid']);  
( C4 Z  O& g; A/ p9 H           $modelinfo = $member_input->get($_POST['info']);  
) b  P$ B( W* }2 ?  h           $this->db->set_model($this->memberinfo['modelid']);  
; H0 ?' D) Q3 f% b0 ]           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  % h% ]+ v1 r. z0 x
           if(!empty($membermodelinfo)) {  9 V1 ^1 d" i% q  A5 h" e
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
+ R1 c  R7 d5 e* x           } else {  
0 H: W  i, u* n( g! D              $modelinfo['userid'] = $this->memberinfo['userid'];  - P" H% t; V2 r7 g; `
              $this->db->insert($modelinfo);  
+ {& f9 r7 N$ }           } 9 C% J6 C( i, k& ^
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,/ P! M. K3 O1 y( s7 F2 d
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
3 J8 g. ?  j3 W, `6 `- ^
1 y8 y: `. w( y+ s1 w# R' t* {5 \+ ~! j& J7 n
9 @$ [$ Z. ?0 m; I
function get($data) {  . Y8 M7 }( Q, I. \; }
       $this->data = $data = trim_script($data);  
6 j& X1 Q1 A/ g/ l. `5 y+ t       $model_cache = getcache('member_model', 'commons');  8 v: H+ J9 P" @: U5 Q
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
; K0 [5 @/ ?& u       $info = array();  
& W, }% I4 M+ K       $debar_filed = array('catid','title','style','thumb','status','islink','description');    H8 k. p& l9 q8 d2 w4 O) I
       if(is_array($data)) {  ! J4 I# ^: F5 h( }# u$ k0 y+ t( N
           foreach($data as $field=>$value) {  7 ~$ ]! r) H  p2 x
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ' s) x8 F4 h2 J2 n3 i0 v
              $name = $this->fields[$field]['name'];  
! }) m5 D  L) S6 L: p' w              $minlength = $this->fields[$field]['minlength'];  5 m& w  R* k1 |1 w* w
              $maxlength = $this->fields[$field]['maxlength'];  5 [4 Y" f: a8 M1 y6 I  K) U
              $pattern = $this->fields[$field]['pattern'];  , B$ E5 y+ g2 c$ u
              $errortips = $this->fields[$field]['errortips'];  
6 s: u9 P/ A' U* ^& C              if(empty($errortips)) $errortips = "$name 不符合要求!";  2 t4 q- F) Q: U
              $length = empty($value) ? 0 : strlen($value);  
& ~6 O9 U  i/ w5 J: |# A              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  " f+ G& g8 T. i5 [7 F8 U
              if($maxlength && $length > $maxlength && !$isimport) {  6 u; v% k" m4 `4 J8 ^' o0 R
                  showmessage("$name 不得超过 $maxlength 个字符!");  
8 Q: i8 G  l3 L" _              } else {    k, C' J0 r# T* c
                  str_cut($value, $maxlength);  ' p/ i4 ]1 L, s" P  u8 j7 X
              }  
/ [* }' W& @6 P7 m. u' |              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
+ K* N4 F: u* S! P" h) s* u                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
& A& E' [( _  s/ z7 O7 [              $func = $this->fields[$field]['formtype'];  
. Q( n3 k3 V3 d' n              if(method_exists($this, $func)) $value = $this->$func($field, $value);  5 N0 m% t& \- Z4 V/ \
              $info[$field] = $value;  " a3 l' `4 ^: D+ d3 `6 l
           }  ) H4 b% E' p" N% s
       }  
. j- w% O( _  L, Q/ b# P       return $info;  
* u( F2 a  N7 D. y" O, ~( v    } - K% k1 a; I8 K# @& i& d
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,5 l4 p* F3 P0 B: \$ U$ Y, w% U

% s) N# E3 H  h' E( C再到phpcms\modules\member\index.php 文件account_manage_info函数7 p% N+ \) ~5 x7 @$ B; h3 z9 m
过了get()函数之后。
! K& p" U- O' e6 R
" |9 _" u( v& I) N5 P5 r
1 x7 z6 c! Q3 D$modelinfo = $member_input->get($_POST['info']);  
/ J* `5 Q9 v! I# K5 ?# R           $this->db->set_model($this->memberinfo['modelid']);  
& ~; p( Y6 P$ z3 a           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  0 ?  o9 ~9 P* p. u: p9 b$ w% p
           if(!empty($membermodelinfo)) {  
+ @0 z% R+ f6 E7 f              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ' v8 X3 v  |  `
           } else {
6 L7 r& ]8 s# L8 A直接带入数据库,update函数我们跟进看看5 |! N+ @* q0 p4 w' j! Y" Y. I

( ?/ \+ Z# v$ d2 g+ Z6 e0 W 8 c. g0 X1 E$ ]. C" ^
public function update($data, $table, $where = '') {  
. b. r  e) \2 v/ D# c       if($table == '' or $where == '') {  
' B+ x. f% B1 U. m$ Z           return false;    i8 X( N7 u! Y/ l7 k* L* v# D) h
       }  
5 g+ @  Y* X: `9 ~9 w       $where = ' WHERE '.$where;  ; b) n3 z" T$ P$ Z4 F
       $field = '';  # j" ]: x9 R2 _+ L
       if(is_string($data) && $data != '') {  % M+ _, p9 l" b6 C  K
           $field = $data;  7 Z) ]! k7 Y2 g$ N+ j2 }
       } elseif (is_array($data) && count($data) > 0) {  
4 I, n" H# X' N           $fields = array();  
1 Q/ [7 ~+ L, O9 B% Y# h           foreach($data as $k=>$v) {  1 k' l8 y) k" b' f: p7 Y
              switch (substr($v, 0, 2)) {  
1 R# j9 _( @- |, Z# \' l: F                  case '+=':  6 c  W1 w" s  \1 \
                     $v = substr($v,2);  # F) p8 Y/ @+ @. V: K4 S, f0 m
                     if (is_numeric($v)) {  
, Y6 X% f2 W3 n! P7 A                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
& g$ X7 D; y9 g7 S                     } else {  
. q- @4 v1 H' H& u                         continue;  
4 j# A$ i1 z- X& K9 {                     }  6 r5 x+ {5 u7 O1 v$ o5 c/ u6 U
                     break;  
+ S. `6 _4 f5 N! f: g                  case '-=':  
! r5 j: |2 T5 v/ W, {- o* U0 l. {                     $v = substr($v,2);  
0 n* R+ t% y$ R                     if (is_numeric($v)) {  5 l# w) m6 r+ P& E; \( _
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  * S/ K! g) F1 R  Y/ r% n( S
                     } else {  
# E4 @9 p0 Q: e! p: S5 j                         continue;  8 y) i5 v- G4 l
                     }  + B" h9 M; N4 B) N: p
                     break;  ' K, u/ B2 H6 D) ], K1 y$ F
                  default:  ) H$ u; W. ~  x
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
/ Z; y* B/ g, O& L              }  3 T+ n& i$ {- i' L9 z
           }  
- E6 q' h' \1 U8 i' I3 E9 ~           $field = implode(',', $fields);  
% b# z, d% c8 j* N1 D       } else {  
4 ?# `0 X8 a5 @# _7 }           return false;  7 m, {! M2 h; w7 h/ \8 L  ~
       }  , G$ K2 y0 Y2 Y1 K6 ]1 N) r+ j
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
4 D- E, Q7 f8 p! N% t       print_r($sql);  
- ~, x( W1 |/ }' B) o; T  w       return $this->execute($sql);  
9 w- k8 D/ n* J4 P; O, E# @1 v- Z    }
5 a1 ?0 L- L8 D; O, [/ {3 p从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
, u' w* w) n5 f) d+ ^8 i% j' O" g/ B( p: I& p! S
攻击测试:
7 }) D. }5 [2 p5 R( H- b' w0 r' ?* I测试地址http://localhost% {/ w2 Q- O* G" {7 j% O, Y
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
/ [. b) i! M8 C9 w
1 B$ E3 ^. D, |- P" j1 |1 V
% c, J2 v9 j$ n9 d- m4 l4 F$ \# e0 ~& y' c) s  I* J0 I$ n) q
: p9 c2 q9 X, L* R. i
; p4 t# n& i( v5 F

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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