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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
* }; \! |& I' l, V8 M+ [' X4 w) f漏洞作者:skysheep
- P0 Q1 a2 @0 a分析作者:Seay
4 L+ l+ x7 ^. |9 s博客:http://www.cnseay.com/$ ~5 p, F$ j! P+ |$ H5 G7 C
漏洞分析:
6 f/ Y4 @& S" P+ j6 e5 N7 J6 s  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。5 T& K8 A/ J+ c
* _/ ]2 q1 ]5 w6 `1 z6 m
2 W" a! v. r2 o& L) v( M

9 t3 p: R+ _+ o$ p1 Fpublic function account_manage_info() {  # y' K2 j& F) Q3 s  E; G4 |
       if(isset($_POST['dosubmit'])) {  
. w# v1 a- C5 i8 f9 r/ e           //更新用户昵称  
7 q. M5 q1 D# C' c' {' b  P           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  5 G& s& o3 H+ r
           if($nickname) {  5 u) b+ F' V! l: B0 R- N& d
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  $ }- \: z3 K, v- N! g, p* {
              if(!isset($cookietime)) {  % V9 V, O5 {' D0 P9 j* x
                  $get_cookietime = param::get_cookie('cookietime');  1 \+ ^  T. u, \, X( t- T
              }  : {% L3 n4 X8 V5 _" p' \
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
: Y2 |# _( W. t. c$ o              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
5 @, M; b* H0 s              param::set_cookie('_nickname', $nickname, $cookietime);  
8 e* |/ Z" V% U) Z9 V           }  ' P1 M* V4 l% F2 ~4 K+ }; G
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
( H: Y: g! H9 N0 Z8 ~           require_once CACHE_MODEL_PATH.'member_update.class.php';  : X- Y% V" k; l& m
           $member_input = new member_input($this->memberinfo['modelid']);  ' M# s# M+ [" g3 h8 [7 C8 Z
           $modelinfo = $member_input->get($_POST['info']);  % P0 V/ A; B9 G3 ^$ }
           $this->db->set_model($this->memberinfo['modelid']);  
8 z/ Z6 P& H( c0 N% i- I           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 u5 ?6 O  k4 V
           if(!empty($membermodelinfo)) {  
( S* n( y6 s6 m; `: R; b* F5 T              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
5 b; m- `' ?  J; P; A           } else {  
$ W9 J1 {# q8 N& i$ q( @: x, J              $modelinfo['userid'] = $this->memberinfo['userid'];  
  |& T" ~5 [) L9 X9 X" d( }' j              $this->db->insert($modelinfo);  1 C, ?+ ~' [, |  F  l, z, ]
           }
$ l+ g3 E$ m) O2 x: X代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,; y/ l% |' X. D0 o
在\caches\caches_model\caches_data\ member_input.class.php 文件中:7 B- p8 m  R9 m

/ U+ ~' W" m+ [; O
, B4 o7 g+ o  h+ t# p, U & u6 O3 I& q& O: {
function get($data) {  
- a# T" F* z. ~       $this->data = $data = trim_script($data);  / C( T, N- a# Q8 C* F0 L9 q% V
       $model_cache = getcache('member_model', 'commons');  * e7 w  S' A. d) w& i( O# k6 _
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  0 D( @" r6 Z7 A6 _8 {! F+ t
       $info = array();  + {' v- O! S: u& _& F! |5 H
       $debar_filed = array('catid','title','style','thumb','status','islink','description');    v/ R0 n$ x8 F5 ~& o
       if(is_array($data)) {  
# a$ A9 {* [4 W9 `5 m           foreach($data as $field=>$value) {  - E+ i! @% j" `; j" G, D4 g
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
% x+ {5 I2 }% I( q1 }              $name = $this->fields[$field]['name'];  8 E/ q1 U& b2 _/ X6 k
              $minlength = $this->fields[$field]['minlength'];  
1 w3 z+ J4 w0 V" p              $maxlength = $this->fields[$field]['maxlength'];    p2 R; ]3 ^1 J. z! z5 u+ n" g5 s
              $pattern = $this->fields[$field]['pattern'];  
. o9 a7 N# k+ C5 P& i. e! L/ A, n. y$ b              $errortips = $this->fields[$field]['errortips'];  ) B6 G" L( B# R
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
( G; o5 c, B+ f, d+ T              $length = empty($value) ? 0 : strlen($value);  
. T8 G6 N4 j1 j' |              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  . l/ _! T8 n, o. H- _3 G; r! W4 V; t
              if($maxlength && $length > $maxlength && !$isimport) {  
  q% P& k% g5 c8 z                  showmessage("$name 不得超过 $maxlength 个字符!");  8 V; y" l7 _4 |
              } else {  - z' m: v7 Y; Y( [. p" h5 U; T
                  str_cut($value, $maxlength);  
4 [( D1 d! p! v+ t# A8 W& a              }  
5 z8 J7 E  b7 a* V- |              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! D6 @( t0 n) J- L* `2 s
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
8 P  m. N9 \8 j$ |7 D6 E! E) c              $func = $this->fields[$field]['formtype'];  % r6 ^+ G" {2 I
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
# T4 q, b' [6 [) O% E- U              $info[$field] = $value;  8 r: I) _0 s3 m" Z9 F
           }  ' @7 ]2 j. f$ q$ y8 o
       }  
) \9 L5 q. R& g       return $info;  
0 X! \1 R+ K2 X: o. D    } - d" v$ s% Z- |. B# ^
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,, t( j. a/ S$ u' |5 ~( V; V4 j
8 w& y: u6 j3 J0 T; [  f4 L5 w
再到phpcms\modules\member\index.php 文件account_manage_info函数
/ |  T5 T2 g! D0 Z9 [过了get()函数之后。8 ]4 r9 W5 s; P4 ~( z
8 E3 q4 W  N6 H3 J, J

! P* W1 `9 Z( v( G1 f$modelinfo = $member_input->get($_POST['info']);  + o$ l" w! f0 {% v+ Q8 c, ^% @  x( u: s
           $this->db->set_model($this->memberinfo['modelid']);  ) m6 h' i* p: J/ y. ]5 W
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
! [/ N4 Q& d' U+ }2 j: q  Z; _           if(!empty($membermodelinfo)) {  / K- {7 r, D$ u  u; F6 T% T  I9 s
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  3 m% D% I8 ]! S; s# J
           } else {
; r. e8 i1 A' r) Z- w直接带入数据库,update函数我们跟进看看
; M, V: s+ U) I7 {! N0 \) M3 `# w4 j9 V1 |* Q4 Z
  z( I2 i$ w3 w9 B) x
public function update($data, $table, $where = '') {  
' g0 M! x: h9 v* |( e. k, U       if($table == '' or $where == '') {  1 y* l8 b& n- ^& X' k9 N
           return false;  
; b$ S/ Y- A$ A0 V4 P       }  
6 v0 _4 t/ p/ ^5 o) o3 n! `4 f       $where = ' WHERE '.$where;  6 l3 r& Y" U2 X7 K) o+ a5 s
       $field = '';  
" p3 g9 K$ ~+ U( |       if(is_string($data) && $data != '') {  
+ j/ ^6 Z& @: A8 }. s           $field = $data;  
0 }- p  r( G7 a" j& A) q! [       } elseif (is_array($data) && count($data) > 0) {  
% w- I* S  T3 T0 K% _7 e$ x' p; L           $fields = array();  
4 w% O- w1 a/ e3 S4 U+ U3 }3 m1 F, D/ s           foreach($data as $k=>$v) {  
% l: B8 t# h8 q5 w              switch (substr($v, 0, 2)) {  
, a0 F: l: l& ?                  case '+=':  & V6 r5 F0 C3 e0 w# O+ V+ z
                     $v = substr($v,2);  
. h7 C# j: f' Z; F+ L6 V                     if (is_numeric($v)) {  ' |1 v7 e$ p  j. W/ r: C
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ! c  c. J" ]* t
                     } else {  0 p4 J( D$ Z: V, P6 Q" f
                         continue;  
/ d8 F) @- S6 G                     }  # k. u+ }$ u1 T; g: ?8 a' ^" E& t* G
                     break;  
" J) w; w; F2 r                  case '-=':  1 p  _$ b5 J0 a+ o6 `
                     $v = substr($v,2);  ' \9 j* _" v& f3 a6 e6 B  c
                     if (is_numeric($v)) {  : o2 l* w* P6 W
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  0 J, i: h, r9 G2 V6 ^. Y
                     } else {  
( k' E/ k3 i# i$ n% L                         continue;  
6 g; t+ }% E: m$ I. l( y  v                     }  3 U9 z- E- v/ K* L8 M7 E; Y
                     break;  
$ d  h# R/ T7 L                  default:  
0 B7 M) M5 E" _4 s  G1 Q                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
: Q" G$ G) O# m* L7 |              }  
' j- @* w/ p5 V; P           }  ) \% s. t% ^' H9 C  m# E
           $field = implode(',', $fields);  
" h' a3 z! C5 \4 a/ q+ d7 i1 G/ x       } else {  
: d2 L9 k6 }' i$ [, v) a           return false;  
+ @: Y. o3 N2 o! ^6 n1 I0 o+ ~! s       }  , r; _3 m+ O( L, C$ F- q
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
" m1 l& o: M2 z5 z       print_r($sql);  
, z+ e; ^4 W0 k. p/ ~       return $this->execute($sql);  ' y6 a7 }( ?! y5 g( A2 P; v
    } / I: ~0 X( y+ y, }
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。1 F) P, F9 C9 j2 [- p

: r+ E; D% Q) c6 c9 S, u( V; t2 i攻击测试:- T# |2 q- `: [5 z. U& _
测试地址http://localhost
. E5 S5 l! b: f. m  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
: o' w: @! z* Y1 w& T# i/ |1 o/ b$ x) K4 j4 V0 B3 ~
; G' C: C  U6 {! d6 h2 c5 w
. j9 x( S8 S( ]' H1 i
5 }* I. W$ B$ V" a0 Q& ]
6 o. P: x! X! Y' i% a

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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