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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告1 }' S- }! b  J7 A: m% f
漏洞作者:skysheep1 ^9 v$ _) x5 k! d4 f5 ]
分析作者:Seay( Y' k5 s) r3 X7 U8 t3 K, k9 N
博客:http://www.cnseay.com/
+ o+ @" W; ]  ~5 v4 z/ `漏洞分析:
- w4 Y5 ?; M5 v3 ~( O8 f  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
4 {3 Y4 j2 n2 j& _6 ?* E1 s
9 P. Z9 {2 i; O9 h. d- A2 K1 e$ R, ^/ G, @

/ S7 f( I# q* D$ E+ }public function account_manage_info() {  
& O8 U2 q- C" f  X5 o, e# a# J+ R       if(isset($_POST['dosubmit'])) {  
5 u* ~" P; f( @3 S           //更新用户昵称  
6 A+ \  `2 M9 j9 g# |* z) p           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
% }! C6 s7 P& M" }2 s5 z           if($nickname) {  
1 c  l( D' K, Q2 j( d5 w              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  * m  Q9 h$ d$ b# I
              if(!isset($cookietime)) {  - i+ W! ~4 S4 }- h
                  $get_cookietime = param::get_cookie('cookietime');  
( z. L& Y$ _4 i/ S* k# u4 B              }  
. H* n+ k0 r5 L7 }+ Q% E7 T6 U; x              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  + z3 E7 S/ ~9 Z$ C1 l8 W
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
. `' T% N: a( R- X8 x              param::set_cookie('_nickname', $nickname, $cookietime);  
3 _2 N0 {0 A+ S. D. R' p! c           }  ! I+ l; Z* I( y! X! c
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
& C! n! A1 a6 m  L           require_once CACHE_MODEL_PATH.'member_update.class.php';  
7 s4 Z6 a% W( e+ D           $member_input = new member_input($this->memberinfo['modelid']);  
/ t% U, h4 l' ~5 A) ~* a           $modelinfo = $member_input->get($_POST['info']);  & \( X( L' P- @0 R: n
           $this->db->set_model($this->memberinfo['modelid']);  
. O( x8 S$ ~. _/ J$ W           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  6 l7 P2 F8 w$ i
           if(!empty($membermodelinfo)) {  5 E# q3 J6 F- k+ d( w) A  w
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));    h! b  t1 F1 ^4 z; X
           } else {  
( `1 n5 B& v% d: v              $modelinfo['userid'] = $this->memberinfo['userid'];  : u3 |" J( X# ?8 I1 u7 i
              $this->db->insert($modelinfo);    j4 o! s. F. P+ X* O
           } " c& F1 v6 g1 h9 Z) V" k
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
3 K# ^! W0 L5 G5 Q( X9 n( A" a2 w在\caches\caches_model\caches_data\ member_input.class.php 文件中:' D0 {: X* B- g
# F4 t( Y0 S, _0 r1 w+ A
* j: a* e: d" ]9 X5 o7 J; g) ?
; K0 X9 Z" f7 y8 b$ e% l) ?) v/ T/ n
function get($data) {  
2 N) N% A3 p# `0 X8 U       $this->data = $data = trim_script($data);  
/ b  N4 x; ^' f       $model_cache = getcache('member_model', 'commons');  
  h$ v( D: z: V5 U- `) N2 D& Z' z       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
* O0 n% A* R$ x; U9 E       $info = array();  1 h: M$ p. C1 p, Y, ?2 o
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  + {* b- }% ^# I1 q( h  Z) N, @
       if(is_array($data)) {    O- H2 K: u! U6 f- y
           foreach($data as $field=>$value) {  
, Y( ^# `3 Z* g! u2 \- _4 Y              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ( ]* g' o# }' T6 {/ M
              $name = $this->fields[$field]['name'];  , c2 I) I4 \: w
              $minlength = $this->fields[$field]['minlength'];  
& \# e! H# S" Z              $maxlength = $this->fields[$field]['maxlength'];  4 a2 _  P5 u. ^* S2 S
              $pattern = $this->fields[$field]['pattern'];  
6 \# z9 u  F" |7 n) S3 I1 s              $errortips = $this->fields[$field]['errortips'];  
  s3 f/ b! }- W/ s/ @7 S              if(empty($errortips)) $errortips = "$name 不符合要求!";  
% x9 ?7 Z& M' ~! k& f# @) g3 a              $length = empty($value) ? 0 : strlen($value);  
2 N. P6 f' T: {, `$ ^" `              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");    x, R  _5 s. h# @; `( k6 H* K' b3 X
              if($maxlength && $length > $maxlength && !$isimport) {  " U( f/ o2 b# P# m: y
                  showmessage("$name 不得超过 $maxlength 个字符!");  
* h; x2 u" c- K% \7 ^* w/ ]( m              } else {  ' E, u4 f" M" ~! y
                  str_cut($value, $maxlength);  # ?% F- n3 S) _3 h- {% O% ?' n" d
              }  
/ `- f' O3 S! |              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  - J3 D* P3 z  Y" k( K
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
. `: ]' D; h; U5 |" J7 V              $func = $this->fields[$field]['formtype'];  4 \: y2 j# Q8 d- \1 Y) V0 R
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
7 t8 }& @. R- L6 Q9 S% o/ t1 a  w              $info[$field] = $value;  : a0 e$ J9 d5 v
           }  
6 d- ^3 B) u* {8 [2 a+ i: ]2 B       }  
2 |# ]7 E3 K2 T; z$ \) x# d' b+ z1 W% U       return $info;  
, s4 g7 K$ _1 [    } " D$ Q8 f- i$ V& K
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组," E$ u5 a% y0 |7 P2 Z

, y  k2 Y. ]- Y) j, _6 `再到phpcms\modules\member\index.php 文件account_manage_info函数9 f( `- `$ A8 s) M: p% K
过了get()函数之后。! T" D& G+ {/ `# x+ b

0 @3 v3 A1 `) E$ E. C" m   F% |4 H% x6 U+ L" P9 L
$modelinfo = $member_input->get($_POST['info']);  / E' u9 c8 w: O4 Y' Z% K1 V4 i
           $this->db->set_model($this->memberinfo['modelid']);  
2 J1 j8 Y: H# Z5 g9 n           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
% t7 C( k1 B( b+ o( a5 v9 ~5 k% [           if(!empty($membermodelinfo)) {  
! u" [& B% _( t" g              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  , \/ ?6 j5 Z  Z! k$ j9 V
           } else { 5 l2 B* r% a- O/ z
直接带入数据库,update函数我们跟进看看+ m  w& `* O! k5 o5 Y' T% ]) Q
5 G; M0 `3 L( W. G3 j$ B3 E

  C( V: L8 T: c+ cpublic function update($data, $table, $where = '') {  
1 m* d* z% o0 c8 {4 U       if($table == '' or $where == '') {  ' E, k+ \0 i# D/ w1 u$ y/ v! U7 u. V
           return false;  
1 X( \  T2 |0 C# \       }  / B& E7 t# M' z& \" n2 q" c& M
       $where = ' WHERE '.$where;  & U5 f9 H. Q! P% @, ]
       $field = '';  
2 \, P. n- l0 w! U* B       if(is_string($data) && $data != '') {  
0 F# P. ^& N% l- u( T4 {           $field = $data;  % f! K+ i; p9 R1 }
       } elseif (is_array($data) && count($data) > 0) {  7 w4 m' A# Y" l# N5 R+ w
           $fields = array();  $ K3 \! G0 l& ~6 h& h
           foreach($data as $k=>$v) {  
6 N+ p4 i5 H" l$ P; S              switch (substr($v, 0, 2)) {  * T. A' t& q2 H% i  B
                  case '+=':  
5 @( j& a7 R  c: Y) G; h: r                     $v = substr($v,2);  
4 ?4 @8 N2 k) y9 }' ~& W                     if (is_numeric($v)) {  7 i. p9 k$ Y9 G0 _; Z) u8 n( [* D
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  : x% N2 a; D  x9 G3 C( H
                     } else {  
! u5 y& }) S# S7 [) I$ Y4 s5 ~                         continue;  ; L" k: I. c" m; s: ^0 r- F! U
                     }  
5 A9 t8 y3 [6 e$ M                     break;  
8 M+ p& x( {6 s; z# j: o                  case '-=':  
% q; U0 w4 I& ]8 ]' {4 [                     $v = substr($v,2);  
3 f  {& C5 X8 |/ v, w                     if (is_numeric($v)) {  
4 J3 T* B+ L% }! n2 i# ]% a                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);    M1 P$ s/ o. z" X( a& s2 T
                     } else {  
7 R; @" y% l5 M5 K& x3 r6 r                         continue;  ; c: k2 G6 [1 h7 ~1 s1 v* G0 c' g& t
                     }  7 X0 t5 a( U' L5 |$ N
                     break;  ! w1 `  R/ p) c+ F: x
                  default:  ; X' Q) Z* Y& e5 `4 v' C5 b! j
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
+ G0 N' E+ k8 p- v; M; V              }  
% ^8 l8 ~8 n; Y) T           }  : ~3 O, m, y, y, u
           $field = implode(',', $fields);  & I; p6 p  f% n
       } else {  1 C, O. r8 E8 {# ]5 g7 i
           return false;  
7 ]& P- y$ |! K- S+ `       }  
, `7 m+ _) S3 G' x- t4 |       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
: x& A# ~: r$ k! k' f       print_r($sql);  : m2 I4 X  v5 K& i+ z5 J3 X
       return $this->execute($sql);  3 v# z  o) @8 x* p' `; E  `
    }   S( d% R, c/ b4 t. q# B9 g4 N
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。2 Q! p# M( T8 I( c% u

2 ~4 q( r% N/ j0 M0 Z攻击测试:
; W- |$ Z/ `( V  _" z% }/ P测试地址http://localhost! s7 Z; |& F1 G1 ^3 n/ R3 c
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
9 h0 ^/ {4 K1 h- L$ M; _& B. c: W2 ]
+ P' _+ L8 R9 n ! ]0 G) f- c4 U( g, W4 J$ n$ b
3 e6 ?9 [$ v1 r. Y) ?; U: g
7 F! `+ X0 @4 m

1 o# S. @6 H: L- X; Z% v

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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