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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
; U! {. {- Z+ |  l# }漏洞作者:skysheep" E8 F) R" t* [. J5 M" y
分析作者:Seay0 R) e8 y4 w0 }9 c+ F
博客:http://www.cnseay.com/
1 e8 H3 H6 k* X6 D漏洞分析:
  O: N+ b* H& T5 }4 v7 C  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
  H* ], v1 k! _5 a. Q7 S$ A
. c8 G5 O- D/ G! V# r' _; x; z$ g+ `9 x* o; n: B& T3 Z

. T8 f$ |' a* [9 F! apublic function account_manage_info() {  
# S9 l. D( b! f! ]( B       if(isset($_POST['dosubmit'])) {  
+ L  @0 l/ e0 q6 f1 S# X  h           //更新用户昵称  
6 E1 o9 p( w8 R' j( c- K# {% h# l           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
- H$ F6 \& P/ i: I* \) O. f0 {           if($nickname) {  ( |) t1 V' \# F* k$ ^( B. a
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ) ?. ?, ~1 g" L+ Q/ D; y3 c) L4 B
              if(!isset($cookietime)) {  4 @, x% k, D. U
                  $get_cookietime = param::get_cookie('cookietime');  
; k2 ^2 h3 ]# c4 D0 R              }  
4 r+ T3 \! Q) h9 h8 \              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
! E6 H. O' m  A. k# ]' |9 C+ k              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  4 v0 y+ h8 n$ c1 W) ]
              param::set_cookie('_nickname', $nickname, $cookietime);  6 B. ]5 j5 E, E5 K* G, H
           }  4 d! ~% {+ Z2 O# m
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
) t% P/ O, J6 L; I, `2 W5 Q2 G           require_once CACHE_MODEL_PATH.'member_update.class.php';  ! R: m  ~4 D) Y6 j$ u; s. f$ }
           $member_input = new member_input($this->memberinfo['modelid']);  7 J. K$ w4 w6 h% ]( y
           $modelinfo = $member_input->get($_POST['info']);  : `, E7 E. p: ^
           $this->db->set_model($this->memberinfo['modelid']);    W% u' }* ~3 I/ V
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
( i- R( A% ^+ S+ J; p$ M5 h           if(!empty($membermodelinfo)) {  $ u4 K) s$ [- r6 W
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  9 U4 {; X6 H2 t7 E1 Z
           } else {  
  F0 l- e# _# t! F* \              $modelinfo['userid'] = $this->memberinfo['userid'];  8 w. U. a# p, |5 x
              $this->db->insert($modelinfo);  
4 A& X% `9 ?& N4 r( W2 p4 _* N           } ( K# q0 V6 i, m$ P6 ]3 [" |( b
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,# f! Z$ @; \& `' x
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
7 e0 x/ P. |' `2 F% c1 ^( z
7 c- [0 \  C% E) w( v
% y, Z/ c6 W2 d2 B6 l 2 i: w* o: j/ P8 q  S- {& G
function get($data) {  ! J/ N8 n; r* R% I
       $this->data = $data = trim_script($data);  ( v- Z" g4 V! k3 ?% L: |
       $model_cache = getcache('member_model', 'commons');  ' ~$ G2 f! i8 W4 g; y& {
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
& l$ x& _- k1 U/ b7 }4 \* v       $info = array();  
" D1 n# B2 q# X& h# k& B0 z" d+ Q       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
* r) f8 v' }7 N, k1 s! H9 r       if(is_array($data)) {  5 v6 I4 K2 u+ e7 C( j$ j" e
           foreach($data as $field=>$value) {  % y% |& V/ T' I! ]7 n  n
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
0 |1 T; T- k9 R( c8 K3 h8 r- H              $name = $this->fields[$field]['name'];  
( y% m) v, s% ]9 B  f5 n# ~              $minlength = $this->fields[$field]['minlength'];  
2 c* C: s1 A7 @- W/ V              $maxlength = $this->fields[$field]['maxlength'];  
6 O! ]8 a  [+ D2 j" h( Q: j& y              $pattern = $this->fields[$field]['pattern'];  4 b& M% |3 y7 {# N& b
              $errortips = $this->fields[$field]['errortips'];  
9 P! E8 W1 i& }. `/ }( a              if(empty($errortips)) $errortips = "$name 不符合要求!";  + _7 A- x2 O7 T- p) K/ P
              $length = empty($value) ? 0 : strlen($value);  
  T: s7 s7 C5 u" d9 h9 E5 u7 n/ }& ]              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
& N1 N2 W' T2 k: p              if($maxlength && $length > $maxlength && !$isimport) {  
0 b* b+ c8 A7 W  W$ g3 I$ I                  showmessage("$name 不得超过 $maxlength 个字符!");  6 S# d* F2 F0 K/ M; E
              } else {  ) X% V5 w6 e) w8 B3 B
                  str_cut($value, $maxlength);  
9 K. T7 J7 \! M              }  ' m5 i+ p' y3 {7 F7 U) Y
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
6 |( E: O8 V: Y- r8 O: `                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
: y: {* b5 E, H+ d% h4 `: F$ _              $func = $this->fields[$field]['formtype'];  
6 o- f% n* J' u3 i1 R% X  W              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ! j* V- r  j* A, b; t! g
              $info[$field] = $value;  
$ G3 S/ P5 B5 _; i5 E           }  - v1 _% q' _7 m/ d# J: f0 c7 ?
       }  
) T  b, e. P( `8 p, \0 e/ x: \: V       return $info;  " z0 _7 u( q  `4 [  v- W! ?. [
    } 2 }, ~. N. C' A2 R; \$ M
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
$ K: Y6 y, x  ^- V/ Q# K! S! ~
. [( n) o4 f0 |* l( b/ T/ _再到phpcms\modules\member\index.php 文件account_manage_info函数/ I) _5 g% H& ^7 n+ G: c3 Y
过了get()函数之后。0 f8 D2 j' y* _5 C
; [) T8 X9 ~6 N; G( f
* L. M5 F5 Y9 B+ ~6 `$ t: {
$modelinfo = $member_input->get($_POST['info']);  
( B; m* d- x8 F/ h2 V           $this->db->set_model($this->memberinfo['modelid']);  & j1 q# P* T# R+ q( E
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ' d; r' W0 m% l. L6 ~8 A
           if(!empty($membermodelinfo)) {  " o1 ]  h$ H$ r! G# T% Y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
" h# Y# U: t  L( o# p% @# g           } else {
8 ~* [& D! m6 x% G! C/ l直接带入数据库,update函数我们跟进看看
0 P: C0 q7 Y# E2 F/ g/ K. M" U/ v! a! @$ H% A
  V) d- R) p6 E: }  K. Q9 O' E; R
public function update($data, $table, $where = '') {  0 e4 G- T4 I3 B# G
       if($table == '' or $where == '') {  
8 }( \% v/ R/ d- R% b7 x: j! ^           return false;  & a; a, ~1 F, R# m6 R* i
       }  
' N/ S* |9 ^6 V9 V       $where = ' WHERE '.$where;  
& a  B4 G" R" r* U7 M5 f( R       $field = '';  
" Y0 R+ X% E: I) d- X+ g9 O8 E       if(is_string($data) && $data != '') {  2 M4 k& y# i* {4 w4 C
           $field = $data;  7 l# ~3 t* d+ O
       } elseif (is_array($data) && count($data) > 0) {  
# A! s7 r% ^2 V3 k/ W7 @           $fields = array();  / i  g  `# ^0 I8 H: I+ P, h
           foreach($data as $k=>$v) {  " b5 G3 E. l- I. i& Y
              switch (substr($v, 0, 2)) {  ! S* d% z" M0 o* l% M
                  case '+=':  , w% N: R8 l1 f- ?
                     $v = substr($v,2);  
( V* M' c0 x' L% ^3 v  R6 g6 E                     if (is_numeric($v)) {  - C( ]6 J$ F/ E$ W$ `
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
5 p9 p* i+ u7 x* F' k- a3 {9 c: Z                     } else {  ( F: M8 m& \2 F" z" ^4 s
                         continue;  
- g6 y4 V3 L' s5 I# k2 r                     }  
+ f* E, Z1 D5 y1 z% C                     break;  
% C$ g! r$ M- |8 T/ t                  case '-=':  ) }/ s% M. y: S6 n/ R7 N
                     $v = substr($v,2);  0 H6 O4 _  @" }7 z2 D% q( L, v- w% q
                     if (is_numeric($v)) {  . B7 }4 g3 w! l" b! k, q/ `
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
( z6 J- b; h  |0 L9 y0 H                     } else {  
8 g5 M4 }) o/ q7 |9 l                         continue;  
6 u5 h* T4 r! A: L! w3 M                     }  
3 ?$ ^" [) m0 W; C7 `9 b                     break;    A  k; y" R8 s1 {' h
                  default:  / M" T% Z8 p% E( o& z- ?; k
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  4 r6 Q6 a: ?, U1 o, n1 ]
              }  ( {  H" i( g* B" v- a. }  v7 R3 k
           }  / Z4 R7 j$ ~2 O, i
           $field = implode(',', $fields);  & V# ?% p) {; ~8 q
       } else {  . R; t  P1 M7 }  I6 I2 n/ E4 Y+ Z
           return false;  1 T; ?9 Z. b. g: r
       }  
9 Z8 \3 k/ k: @3 A. T- ], V       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
1 T  J8 G5 A5 o       print_r($sql);  
, k* p8 V( u. x; r, v2 O5 H       return $this->execute($sql);  
# q2 r& v# T) e  ]& K    }
: n1 S: }! X' U: [5 |5 A) x1 Z/ t# |. E从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
8 S* u$ A9 X, z# {) X7 U- L' j6 h( b3 t
攻击测试:
9 w8 h" }- H) S" n$ P) o7 M& }测试地址http://localhost
) ~6 h8 s" I: A& o' A0 d* ~( Y  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
2 @  L1 h  t# l% V, K& m$ W1 ~' M' P0 z- Z) ~6 t0 |: Y& G
& g! b5 l" K- P( b
& P  }1 Q' t# B$ @9 n
7 G- A3 r5 J1 r; R" i0 W
. ~; B; G2 `& L+ R5 V! H

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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