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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
, h% @8 k# m' o# G  E漏洞作者:skysheep- u, h8 h" r9 f2 k6 Q6 F! j( _/ W
分析作者:Seay
+ y( L7 |/ c9 G5 N1 K博客:http://www.cnseay.com// X/ y& @1 u  O9 E5 x, H7 R
漏洞分析:% {) R) P! _9 c2 v- j) a
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
5 w1 G8 D# b6 f5 `& r! n3 I! f5 D, J7 D; u5 W. r1 ]$ G6 t0 |& ?0 L
% r. l5 c! p% H! r) u' V* Y
& @' h( s0 R3 p' y$ L$ S* G
public function account_manage_info() {  ( d+ k: \; ^' a7 s6 Z7 q# u
       if(isset($_POST['dosubmit'])) {  " e2 u! B+ e) J
           //更新用户昵称  
9 T) P- H1 g8 i0 ]% x6 u' D, M           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
& n& q- Z9 m5 v' H; x( q5 Q           if($nickname) {  " Q8 d! X- G  t" x, o( }& x
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
9 ^2 r; Z5 ~5 o0 Y5 C; l; X              if(!isset($cookietime)) {  
$ {/ O* Q  _0 N( E                  $get_cookietime = param::get_cookie('cookietime');  ! V0 ~0 [, B; i# L9 H2 Y  |; j4 V
              }  * ^0 K, U- G# p4 {
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  . A( I- w. k; f/ K7 B
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
  L$ t, c& R& m3 j8 y6 u* \              param::set_cookie('_nickname', $nickname, $cookietime);  
% j' ]8 H2 N1 k/ q  I           }  0 \# x! S# m4 j
           require_once CACHE_MODEL_PATH.'member_input.class.php';  - Y" C* n4 w9 \4 ~% c1 o. R
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
/ p! F( {1 e8 v) C/ I9 U1 b% G. m+ b           $member_input = new member_input($this->memberinfo['modelid']);  
6 G* Y9 E# C* z; F3 x           $modelinfo = $member_input->get($_POST['info']);  
* Q4 ]* d9 R5 u: q' [6 X$ R           $this->db->set_model($this->memberinfo['modelid']);  # `! G+ \' I* s* C6 K
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  9 s- S- e5 _! o+ L. c$ L1 Y8 I+ J0 i
           if(!empty($membermodelinfo)) {  
. t' h( y/ |. X0 m$ ]* ?              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
  U  H6 ^6 W- D, t0 q           } else {  
0 R3 C3 t- c) j+ c' i0 x, o" Z              $modelinfo['userid'] = $this->memberinfo['userid'];    n' z; ]( B/ o0 f
              $this->db->insert($modelinfo);  ; J0 e2 J* a6 p7 g2 C6 q7 X
           }
7 |. f1 l$ D& u6 ^代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
, [6 }  M3 X* v2 `) s在\caches\caches_model\caches_data\ member_input.class.php 文件中:: e. J7 ^4 p7 h! O
  j7 q  D# j% a7 r% x+ r

9 U* t! L$ b8 Z+ G6 a
) _0 z  }$ V3 o' a( g1 N4 hfunction get($data) {  
2 l; u8 M' u: d3 J  V       $this->data = $data = trim_script($data);  
  y8 R9 c  q3 I5 @       $model_cache = getcache('member_model', 'commons');  # J- n8 D. h) j, i0 Q" ^
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
3 m3 S5 O7 h8 K1 j+ y4 R4 O/ v: A       $info = array();  
, w+ o  U/ V& n: W( E& D, O$ F       $debar_filed = array('catid','title','style','thumb','status','islink','description');  + I5 t  L6 V# `2 j& T+ K$ F8 I
       if(is_array($data)) {  
& \! a1 i. F* ^8 y" a5 }           foreach($data as $field=>$value) {  : I4 A/ j6 V8 p
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  * ]& c2 x( {$ v0 u7 ?( p- m, Q
              $name = $this->fields[$field]['name'];  4 M  G3 K7 J) D7 y4 x
              $minlength = $this->fields[$field]['minlength'];  
' p( {: L7 W* a& m% Z3 ~              $maxlength = $this->fields[$field]['maxlength'];  
& E9 r( b+ Y% G              $pattern = $this->fields[$field]['pattern'];  
  _! ~# K; J8 e              $errortips = $this->fields[$field]['errortips'];  
$ n4 V# O3 D/ F              if(empty($errortips)) $errortips = "$name 不符合要求!";  
) F# M) A0 y* m& C/ w5 Q! d4 B              $length = empty($value) ? 0 : strlen($value);  
2 {$ ~3 _& {# z3 H- g  F              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  : g0 C, ?( L' D' ]$ `
              if($maxlength && $length > $maxlength && !$isimport) {  7 c$ |" {+ w* c+ m
                  showmessage("$name 不得超过 $maxlength 个字符!");  
* H7 Z( a+ p' q              } else {  5 G2 c" g6 Y1 {' F% b& Y- F
                  str_cut($value, $maxlength);  6 d; w* L" w/ D5 J" J
              }  & v: |$ N8 s$ K/ v, s0 Y8 V
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
! o7 Y& _* o* c                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  4 p+ J2 T0 G# l$ L# _: M# ?
              $func = $this->fields[$field]['formtype'];  
0 K2 I( M( F) r9 j" K, q              if(method_exists($this, $func)) $value = $this->$func($field, $value);  1 p# |' i: X3 w1 F. x- c3 B
              $info[$field] = $value;  
: T1 n& u# n4 P9 Y6 m           }  
9 Q2 S' \( i3 d( D4 v       }  0 V% u0 P1 q2 r0 o8 ^
       return $info;  
0 ~: g6 w: y/ f9 h8 w' A    } ( y& F& @5 s" y7 Y
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,- E0 C9 t( {8 a( {9 d& o

; q$ U! H  t1 l( X: Y) `再到phpcms\modules\member\index.php 文件account_manage_info函数7 n% F1 I& X9 A+ x; j  \  I0 \
过了get()函数之后。
3 Z3 D# H) f  V9 |8 l8 d6 Y
7 h# z/ E; E/ S   ]# {7 @# m7 F4 M$ Y
$modelinfo = $member_input->get($_POST['info']);  
& l0 o' C* P! w* ?& L3 u           $this->db->set_model($this->memberinfo['modelid']);  
7 K2 T& K! `' [& u           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
) T: C) _: M1 Y7 W           if(!empty($membermodelinfo)) {  ; _6 X7 H7 ]: ]7 r( x) U1 J0 H
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  + w5 M+ K* E/ x
           } else {
* e# k9 B: e2 t. @; O8 g直接带入数据库,update函数我们跟进看看
5 K9 q$ g! y" Q7 L9 ^! z
$ h5 Y( G# a2 i  O: O; f: O $ R6 Z0 f( {0 f4 F! c# e( v
public function update($data, $table, $where = '') {  5 I& `1 K% A+ r; A6 r
       if($table == '' or $where == '') {  ) L5 O; I$ s% l% M% Y
           return false;  8 g1 q: Y8 K% Z$ x% u  T6 z
       }  * F* Y% [3 r2 T7 l) S& U: p2 f: K3 r
       $where = ' WHERE '.$where;  ( K. P+ v  A. Q( f- v' ?  R
       $field = '';  3 l$ G( h2 @* G1 }
       if(is_string($data) && $data != '') {  
1 X" B8 Y" {- _! i           $field = $data;  
9 A' v6 ^8 R  }2 T  C# n0 b       } elseif (is_array($data) && count($data) > 0) {  - a% g" F7 @7 j5 p
           $fields = array();  ) \* P( k2 G+ Q5 D- M
           foreach($data as $k=>$v) {  8 w* c& ?4 o3 ?
              switch (substr($v, 0, 2)) {  ' G; g# X9 g9 z/ f
                  case '+=':  
' f0 t3 k: `$ l! @+ v- K                     $v = substr($v,2);  & V+ q. C* k) @! J. W7 C/ N
                     if (is_numeric($v)) {  ; n1 i: L5 O- b3 B. d2 \, X& [
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
; W6 {' P3 x% a( Y, k4 ^4 l# R                     } else {  ' n$ e! C' G- i
                         continue;  
2 g+ [) |2 v% o- E  A; }+ E$ d                     }  
9 ]) V/ |2 q; I0 H; H                     break;  7 @1 L7 I' s* S% L) U
                  case '-=':  & d/ ]0 r' M4 O- n. R9 \
                     $v = substr($v,2);  ( a% f  V5 Q& D( ~# h+ n
                     if (is_numeric($v)) {  
) C  i0 [2 a1 m3 R& B- G4 o6 x6 @                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  $ V+ a6 X6 L' ^& P" n
                     } else {  
; |+ w5 r# g; W* U                         continue;  
/ {+ A* M$ f% K2 a8 O3 f% d6 c+ T                     }  
; l3 d* m; k! v; S+ X                     break;  % v" @9 T. g, B7 G, i
                  default:  + D- r+ j6 |: I: o) l
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  : s& n- Z# z! @; k$ G0 e2 J3 b! d
              }  9 c" C  B: n/ S5 k
           }  / S% ?+ B* f  d# U: U  C' S
           $field = implode(',', $fields);  
4 |- W( F/ ?+ F       } else {  + j& X( T& }5 O# e' ]$ Q0 e; K7 G
           return false;  0 }, D  p1 T+ e( k% Y7 ]' M: _
       }  
/ m2 R; \) c* O  n! p       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  $ H' [; Z' G) R# W# T' v/ b3 v9 z
       print_r($sql);  ' _- p5 {+ R" x! ?! ?9 N
       return $this->execute($sql);  
: }1 M% W7 F7 e( R% U- B/ u3 @" f    }
' d  ?* H. R8 A+ O$ G: q% L从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。1 D6 u% C, i6 p2 D

, }( v" J- r$ F# @攻击测试:
1 T0 A0 X1 f' L: Y测试地址http://localhost$ w$ R5 K' o9 X4 d2 O! L
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句1 v( g$ X: L: u2 y0 Y. M# N* }
! ]% t5 C4 J6 v
  B" U0 q( V, X6 \7 x0 h
; w. J" D' r) l

* t$ l7 W9 u8 X7 V% {. ~7 [2 p; v, i. [- R% o$ O3 c

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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