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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
" K' ^/ T; v' q: d- X3 G漏洞作者:skysheep
6 l5 B6 C" [) z4 D1 O' E分析作者:Seay
% k' i& d1 V- f8 |% ]博客:http://www.cnseay.com/
" f' ?" I8 G5 Q$ x漏洞分析:9 `. R# @4 L1 u, W5 w
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。& v0 d) D+ V  Z; q3 u1 @3 B3 v
5 q  ^9 R  W* y

9 M% v8 O* V1 w$ q) y % Z7 e; }3 R# q: _. S& `, Q1 A! A3 s
public function account_manage_info() {  : B- L2 ^4 J$ l$ }0 @! B2 P5 v
       if(isset($_POST['dosubmit'])) {  
, R6 m% q" F# Y, U( T           //更新用户昵称  ' G4 m$ v' _  p# z) r7 l- }& a
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ) |9 z( d4 f$ `$ i7 j% p
           if($nickname) {  4 B/ l: }# t: T- B+ n: W9 W, J! i( m1 m
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
9 K! J3 B. `, _5 c/ L              if(!isset($cookietime)) {  % f; w7 \0 u7 o$ K: p  P
                  $get_cookietime = param::get_cookie('cookietime');  0 s  c2 ^8 j. v5 l% A) ~3 F
              }  ( ]. K" m3 I% z' S9 Q4 F. P% P/ \$ R
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  7 |" i4 y" H6 o1 A' c) o+ j
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
4 r4 x3 p/ V# E              param::set_cookie('_nickname', $nickname, $cookietime);  # i% j: j& z$ Z. m1 ?: Y& v) G
           }  / x- a3 Z# b9 V  z( \
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
  p  |' V% u4 T/ X) f1 D           require_once CACHE_MODEL_PATH.'member_update.class.php';  
: @& @$ c% U  }  e           $member_input = new member_input($this->memberinfo['modelid']);  8 v$ q9 d* j5 p
           $modelinfo = $member_input->get($_POST['info']);  
; P/ V- a9 q5 D+ A% M           $this->db->set_model($this->memberinfo['modelid']);  5 `1 q* n0 J$ q) _3 ]# q
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
: }* T% j9 e( Z% R( j( k: W           if(!empty($membermodelinfo)) {  
, c& O4 n7 T. X- v6 l              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  2 |2 w( F, R7 m
           } else {  & }4 p/ P  _4 [5 J
              $modelinfo['userid'] = $this->memberinfo['userid'];  ) X& _# ?" J( r( k- }) j
              $this->db->insert($modelinfo);  ; ]( [$ Y- [. h6 V0 ?& b3 g0 F/ a
           }
2 M% d+ {& L+ {/ ~3 Q- E代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
1 |& T1 Z* F' W% E在\caches\caches_model\caches_data\ member_input.class.php 文件中:
. S) |7 u7 I, Z3 f) L5 S3 n* E6 \1 V! U9 a3 C* I" Y

* v( o: q' r+ [( I: Y4 @
" l8 i# e; r: f0 \4 Dfunction get($data) {  " u: S+ L0 @1 l. n- k( O
       $this->data = $data = trim_script($data);  8 R3 {* r8 X0 n2 e; I; G
       $model_cache = getcache('member_model', 'commons');  
8 p, X+ b' N9 E       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  % p! v6 d- G1 b0 D
       $info = array();  4 @" ~- Q9 A+ ^
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  + i; [4 d) m+ S6 ?$ B
       if(is_array($data)) {  
4 N4 z) h. M8 O, h4 N3 n           foreach($data as $field=>$value) {  
% g% C1 O! }4 m0 s; t$ ^" C0 r0 M# ^              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  9 d4 T9 H# b& x( H/ T  z% w4 h
              $name = $this->fields[$field]['name'];  
# Q6 d$ k" j+ F( v9 [* F6 X2 G) \              $minlength = $this->fields[$field]['minlength'];  
4 D& i/ t8 @6 z/ }( k7 Y              $maxlength = $this->fields[$field]['maxlength'];  
3 T) f- U* M# Y+ P" ~% O              $pattern = $this->fields[$field]['pattern'];  7 K! N, G6 x/ y- V9 ^1 Z
              $errortips = $this->fields[$field]['errortips'];  2 W- O- j# e" G/ y; X2 s: e
              if(empty($errortips)) $errortips = "$name 不符合要求!";  6 {! R! E3 J2 f
              $length = empty($value) ? 0 : strlen($value);  
, c1 I0 Y6 p. A6 a( y# H; t: A              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
, A2 K% l( o/ x              if($maxlength && $length > $maxlength && !$isimport) {  : H# @, X0 M% }" h! J' ^$ `, \0 G
                  showmessage("$name 不得超过 $maxlength 个字符!");  
3 \" ]/ k9 f; ]  P* a3 C              } else {  & V9 f& D1 N+ P% N. v
                  str_cut($value, $maxlength);  
' r, a3 u. l3 @; k8 `2 x              }  
& X3 `7 W* n! G' U% D: m8 W' W& G; x              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
5 m/ g) }; D$ u& A. q1 S  A) f                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
) q* S5 P) `4 b              $func = $this->fields[$field]['formtype'];  ; r! M+ C% s8 A& v" ~
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  - A, z2 T  D; v5 n! f2 S. e
              $info[$field] = $value;  4 E1 j, }- q( S5 Y# l% O
           }  
6 M# A3 _9 z! U       }  # \* o8 U& m$ [$ T
       return $info;  4 x  v. f& G) e' q2 b8 z* Z
    } ( n$ m5 B1 l! \/ {4 m
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
4 }, C5 k' z/ I4 {* z- c1 U' g+ `/ j0 [6 u; G, H+ z, G
再到phpcms\modules\member\index.php 文件account_manage_info函数; \. S# r8 {* J; \& J
过了get()函数之后。& I/ o0 T% a1 H3 _8 U

& B# G$ S; s- Z+ }2 E 8 ]2 F3 X# |. G* l6 Z2 m
$modelinfo = $member_input->get($_POST['info']);  6 W# v2 l2 g- Z2 V
           $this->db->set_model($this->memberinfo['modelid']);  
( ^5 B3 W& G9 I/ Y2 R. B) ?           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
+ g; A' L5 j6 x7 x           if(!empty($membermodelinfo)) {  
3 V2 ]9 w4 k0 e4 I              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; t+ @, i1 X$ `7 s+ [8 X5 Y  e# {
           } else {
0 l" A  Y+ V" H- v" q% p直接带入数据库,update函数我们跟进看看# A; q' E: Q% {; [+ Q

0 ?* x1 s; j# `4 i5 b& s+ J 2 u" C' K$ l4 s' q  ^# `9 j
public function update($data, $table, $where = '') {  ) e8 L1 y0 }/ P" B
       if($table == '' or $where == '') {  ( z9 I9 S1 J0 W. Z9 H' @4 d
           return false;  ! e+ S8 z; X. H$ a. s. I; C! |
       }  
; @5 O5 k) k. [4 y& _% a       $where = ' WHERE '.$where;  
. l1 w% J+ G  M  ~2 q+ a       $field = '';  
# t' x5 [$ G% k$ s6 ]7 K. a       if(is_string($data) && $data != '') {  
( M0 U- H5 j- ?- k           $field = $data;  
6 R% ^! Y$ |( K7 d; `" o       } elseif (is_array($data) && count($data) > 0) {  0 I  G% y) @$ g- ]. {
           $fields = array();  
, r/ @6 ]3 k8 A1 X! U  U( o           foreach($data as $k=>$v) {  
1 j7 R7 h) h- H/ I              switch (substr($v, 0, 2)) {  
" V" g6 g) \) Q. y                  case '+=':  + y7 n0 b: n  K8 G$ H2 W
                     $v = substr($v,2);  
2 C$ a& N8 Y: ?  e, [                     if (is_numeric($v)) {  
6 e! F+ F. w8 G/ g7 h* A% v5 W                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  # L# T" |( j7 [8 e; i3 L
                     } else {  
* u6 \% H; V2 E- Y. A; H( j                         continue;  9 T# v0 ~( A: N) |" C( P6 x
                     }  / l- D3 ~" Y& H9 R' |
                     break;  
% [4 F9 c) n% j- e                  case '-=':  
8 R1 J3 S& l. n! O                     $v = substr($v,2);  3 v! h- q$ D9 d1 @6 `' m' _
                     if (is_numeric($v)) {  ) e* H9 @5 R2 p  m, Y8 Q
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  5 j. ^" D! V3 X8 @( a! v$ f
                     } else {  * d/ t8 ^! v8 ^/ S$ U
                         continue;  # B* W7 S2 n( b, r: O% [7 G
                     }  
/ J( [6 w7 \1 U' T: t* S: h6 V                     break;  
1 n  H6 o4 q5 x# y8 o2 J, Z                  default:  
4 L' P$ c& ?. l' W1 s7 X3 P7 i) N                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  8 \6 k% g0 Q# K
              }  
# }  E6 R& A2 f9 W3 B           }  & s( C8 E) g! K9 }
           $field = implode(',', $fields);  8 S4 h9 x! h' {, g
       } else {  
3 i6 l- p6 P. n: ~* s           return false;  
  v) W. c; \3 t$ l6 {       }  
7 e0 R) n1 |! E! {( v5 J       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
7 D: B; h) s4 R" K6 ], M       print_r($sql);  3 v. j3 @4 M5 R. Y4 H1 M
       return $this->execute($sql);  
% R+ E4 c4 ~, s- ^    }   x: Y8 m% {6 }/ ^/ H+ `5 Z2 _
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。3 C8 g2 q: k: h& f

9 V, n1 l6 y2 k1 F8 u* \攻击测试:0 ~3 I. @: U. {$ r
测试地址http://localhost- n8 u" \$ p$ e1 u
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
. y* a5 _1 c# r# m9 y# p
5 Y: C5 z1 k% y
  b$ W8 @' ]9 }/ A6 Q2 q0 {: ^. H
' E% @: E4 h" I' R% g! u5 X' e7 F9 p

: ^" h" Z# _, ~) X& J( E4 }3 c$ G

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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