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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
! ]  J3 K% i# ^/ R- N8 r+ L" e漏洞作者:skysheep
# I) r7 S% \% B& l$ C7 P分析作者:Seay
5 O( f8 v* f3 T# v0 u博客:http://www.cnseay.com/
1 f" K# t5 U0 j8 z漏洞分析:! z; F. T8 V; [4 Y" e
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。0 ^3 _) t# M' O1 G6 k

% v2 e. U, _; f% Q6 v. b
. f8 _" f1 c4 o' ?8 P
$ O( k5 ?( b, G2 A( g! E7 dpublic function account_manage_info() {  # j" M5 M! _& H  N. X
       if(isset($_POST['dosubmit'])) {  
3 B# Z0 J0 F, D  p0 s( a           //更新用户昵称  ; I$ Q5 p$ {5 N' S' D5 w! R; I
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ) z0 i4 Y: X+ o& N" i; u
           if($nickname) {  
0 ?7 t) \  R/ n  u" Y$ S8 N              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  & K. ]4 z* P- v" O% |: f
              if(!isset($cookietime)) {  & j1 D% m3 _2 }  N, m6 R
                  $get_cookietime = param::get_cookie('cookietime');  ( i0 K2 F9 s* F; b
              }  
  d' t- P; A. t* B9 |              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
! Q4 F: E' D2 K* _) K: P5 q" s              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
' e. v: r, y* s              param::set_cookie('_nickname', $nickname, $cookietime);  ! n1 t8 D: T7 y) v, _
           }  , y- q" J( Z" o9 C5 s8 _( O
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
! T( }( O# G4 _           require_once CACHE_MODEL_PATH.'member_update.class.php';  ; j5 K' w- @; b! @6 M8 U2 u
           $member_input = new member_input($this->memberinfo['modelid']);  
7 r/ k, Y8 U5 C" u* C4 t           $modelinfo = $member_input->get($_POST['info']);  
0 |5 X( D7 [! E2 @) Z           $this->db->set_model($this->memberinfo['modelid']);  , S- J- B7 x  t
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ) W( [3 E5 Z& Z- |- n! d. k
           if(!empty($membermodelinfo)) {  8 A5 `9 N; h  m/ Y0 t
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  $ g+ t1 H) s: [7 F
           } else {  
  W  r4 w, M( O% N8 q; I- m              $modelinfo['userid'] = $this->memberinfo['userid'];  2 P! q+ x: G" x. `6 `! m
              $this->db->insert($modelinfo);  ' N* W8 i+ n. V! z5 T
           }
+ U$ K" l8 A7 }% f* N2 ?) E代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,3 H" d6 x( u" z, i" x
在\caches\caches_model\caches_data\ member_input.class.php 文件中:5 s3 P* f- E$ d! ]7 P9 w" b
  p- Z4 B( x1 d* L" m7 t+ x' u

: A- T* \: D$ p7 {7 ? ! v  k0 T7 [, P
function get($data) {  
6 _( t. d& l4 p- I! [7 m7 L       $this->data = $data = trim_script($data);  0 @( K# o7 C& S
       $model_cache = getcache('member_model', 'commons');  
0 h2 a" N+ x3 r       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
% `& N8 Q! C& S# b/ g( k       $info = array();  
. [. R7 f1 L9 I, Q       $debar_filed = array('catid','title','style','thumb','status','islink','description');  / T- B5 S4 ?" Y( Q7 r# E9 \" f
       if(is_array($data)) {  8 V5 K) d' z# N4 F8 o9 }8 Q3 V5 n+ b/ `$ K
           foreach($data as $field=>$value) {  
  D6 n* h8 f) q# ?# |# A; _              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ! q* a# N; V. T5 \" V9 X
              $name = $this->fields[$field]['name'];  . y. t6 X9 U# L' u- Z
              $minlength = $this->fields[$field]['minlength'];  
* i# _. l* A0 r: V              $maxlength = $this->fields[$field]['maxlength'];  
2 w4 z  L5 t. J2 B% \7 p              $pattern = $this->fields[$field]['pattern'];  ! Z4 P4 ~/ k- L  E/ z
              $errortips = $this->fields[$field]['errortips'];  
' C! j5 Y: ]5 @              if(empty($errortips)) $errortips = "$name 不符合要求!";  
( W) h" O7 U& W7 ^+ p              $length = empty($value) ? 0 : strlen($value);  & E/ s/ Z9 c! m/ q5 S
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
' Z) H4 ~4 A" \+ z2 Z9 r' Q              if($maxlength && $length > $maxlength && !$isimport) {  
$ T* w6 q7 J$ x) }2 z8 V" E& q% g% j                  showmessage("$name 不得超过 $maxlength 个字符!");  - C* C% U9 L2 ?% [6 A( F
              } else {  
, u# j' c8 k" L) J                  str_cut($value, $maxlength);  
7 I& `3 A! e* S              }  3 ~+ ?0 U. [4 }
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  % O' \& }5 J3 K4 D
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  , i6 o  g+ n* W; q* B5 G) @/ n
              $func = $this->fields[$field]['formtype'];  
7 }6 ^  Q2 a5 J& P7 ?! k/ t3 f              if(method_exists($this, $func)) $value = $this->$func($field, $value);  5 i: `9 ]+ f' u4 B' A! V8 b/ d9 B- t* p
              $info[$field] = $value;  # O6 j( p, K1 I2 i
           }  
' X% i. s6 ]2 @; u       }  ' H8 T5 U9 M5 y
       return $info;  6 g) M6 A) [! v) t* f
    }   u! E: W" r8 B6 r3 G
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,4 Z! k; k9 c; @/ F% S) t: i, m

, h( O% B% q- N, D+ m0 I0 r再到phpcms\modules\member\index.php 文件account_manage_info函数  X1 l9 r, _0 Q8 ?0 Y, Q0 }# a0 J/ v
过了get()函数之后。
8 f' e" z( s) n' l5 ~& H/ H( N
$ b( p! C( J3 {# M, r, k- H. J
- F' b0 w. o$ R. y$modelinfo = $member_input->get($_POST['info']);  
2 N& K6 V3 m3 l) M           $this->db->set_model($this->memberinfo['modelid']);  * ^  s1 C" W. B" a  N& U! P1 w  v
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
4 D; t9 z- j0 I' x           if(!empty($membermodelinfo)) {  ( n' a8 r0 |8 R+ O
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
' D7 L4 ]! k6 p, t' h  H, V+ Z           } else { ; A* s/ y: v4 g" x% p( y
直接带入数据库,update函数我们跟进看看
( X$ y! r* n" G  X& W6 N/ P. [+ E/ D! O/ K( K# v) F
6 p. T) k9 z8 h
public function update($data, $table, $where = '') {  ' {3 k4 k2 X, P6 ?0 d0 B
       if($table == '' or $where == '') {  / F% i$ E- g# B2 Z9 L# D
           return false;  # D! |! v% R4 c( ~6 h% x
       }  
( v3 J. s" V# F* [       $where = ' WHERE '.$where;  0 m/ Z* C/ R6 S. ~1 _/ D. y
       $field = '';  
) U# J/ i. r: |% C( V' ]       if(is_string($data) && $data != '') {  / Z( K! U5 I# w* T" D/ D
           $field = $data;  
! N5 m: S. {0 q+ n       } elseif (is_array($data) && count($data) > 0) {  
$ W8 N; w1 N6 c! X# l- M! H% y3 f           $fields = array();  
6 F% i0 j; c0 E           foreach($data as $k=>$v) {  
+ K6 v& t9 a2 j$ t              switch (substr($v, 0, 2)) {  
+ k0 l$ E5 E& |! Y% {2 P" S8 D                  case '+=':  
& ]0 z" c0 E. U- J9 B2 |7 y7 V                     $v = substr($v,2);  
; }8 ]" K+ @4 g& A, |( S5 R) W                     if (is_numeric($v)) {  
. @" i# ]: X$ P5 W7 q                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
+ v' ~2 b- F3 y. a3 [8 f                     } else {  8 t4 S$ n9 F3 d9 F) t( z
                         continue;  & W. v  N- y' o0 o7 @! i, {
                     }  % c8 W- v7 v4 M6 M0 ~( L! ^
                     break;  + k; ~, q% M' B, O; Z) G
                  case '-=':  ! d3 X8 v7 [. x: e
                     $v = substr($v,2);  2 O( ^' i/ T# v  \" T  ?
                     if (is_numeric($v)) {  6 Y, ^5 j* h/ ?) V" K
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
4 p  o, S6 z1 l+ ?                     } else {  
6 s& w! X. p1 f4 s  j5 W                         continue;  , E+ r4 M' ?- G! {
                     }  . L; C+ w1 I6 n
                     break;  
- I! A, Z% z4 g5 _* d. f* p7 i2 A                  default:  ! k8 |& t5 r* @) g+ }5 ^+ @
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
! C& ^& n. J. a7 |! h" R9 s) G              }  
- u7 j7 V3 l( v9 b* `           }  
* o+ {. ]/ d; j% G           $field = implode(',', $fields);  ( \- w* ^. g. _5 v9 t9 n9 N
       } else {  
. {$ l6 D3 z- r& ~           return false;  # n) L0 F. i8 I5 c: a# \$ O: X
       }  5 G5 T4 Q; E5 K
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
6 o) {! P/ p2 f       print_r($sql);  1 X2 [6 B4 R- B8 D
       return $this->execute($sql);  
; ~# j( j7 A8 Q7 B: U8 i( x    } : B1 x) w& I, S3 i1 y( r
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
5 l, J4 t& L2 d# H
3 C$ a: w! s4 e: B攻击测试:
; ~  q, s' o6 p7 _2 c$ e+ H测试地址http://localhost  _  K4 q* T9 z& U0 {
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
0 {4 k- @% L3 g: k1 n
' w$ S5 U9 a3 v3 _3 D& l
8 r6 {9 H# x. d( s3 Z& k* {* q  ^+ z4 U1 N
# k9 g% A& P$ N" P, u
  l1 o& u+ m2 |2 P3 P

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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