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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告% B  {8 E: ]% B% Z/ G8 ?
漏洞作者:skysheep
9 p8 w* ~$ N8 b$ }分析作者:Seay# ?6 n( |, p# T7 K4 m1 _
博客:http://www.cnseay.com/
+ [# @; V' g/ a漏洞分析:( @/ e1 A" x* K2 O# ^* k
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
! N6 M/ U, m. a& u, y3 t" j
& x7 V. [* E2 V3 a, P# ~( ~3 n$ }) L' f3 s. T& k
1 C( `8 x) T; J" @' l
public function account_manage_info() {  4 }% I6 A3 f8 U! o0 ~
       if(isset($_POST['dosubmit'])) {  
6 a$ _2 G6 b, p. D           //更新用户昵称  
' m( @; b) f# T+ D6 b* e6 Z+ L. n  k           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
1 j- S, O# u4 R  e           if($nickname) {  
) N' e) B& H5 ?5 j* {# U; o              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
  K& b7 ^; v+ ?0 z8 S              if(!isset($cookietime)) {  * m' ]7 O% u) d$ G+ v
                  $get_cookietime = param::get_cookie('cookietime');  5 T, R( G2 D3 c! K1 i3 _' Z
              }  # K5 `( K1 _' I& }; n+ S4 O' w" [
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  7 R; _5 P) h- c
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  8 \, u) m. L+ c3 o: t! `" A
              param::set_cookie('_nickname', $nickname, $cookietime);  
: j; D! U) ^: z5 l% y5 W           }  4 b4 a: v. O! b
           require_once CACHE_MODEL_PATH.'member_input.class.php';  & [! j$ z, \; ]6 \  l" p3 [
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
# @: F+ P2 }, K+ h# z           $member_input = new member_input($this->memberinfo['modelid']);  
! g% Z9 T/ H, k3 p. Y, J' D           $modelinfo = $member_input->get($_POST['info']);  
- c' S/ ?3 s+ {$ h           $this->db->set_model($this->memberinfo['modelid']);  
( U( v2 K6 D4 Y2 Y" y' s           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
) T' c! A1 |0 {/ f# Y+ u8 m2 O# n) W7 U           if(!empty($membermodelinfo)) {  8 c/ k" l, G6 p" U4 U+ z4 y" {$ H! b
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  , U1 K, C. A7 N+ n( Z
           } else {  
/ k7 v) o/ ^2 E3 m              $modelinfo['userid'] = $this->memberinfo['userid'];  6 S3 k8 I  a: {( h5 Z; i+ n0 @
              $this->db->insert($modelinfo);  
5 `+ m; P6 m6 [& I8 v% @4 M4 t" q           }
' S  e5 o6 r3 ]. S代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,& B6 o3 n, j, E/ T8 I( Q
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
( Z. D) W! s2 g+ p( r3 X4 r5 g3 w6 K" J3 a" ]% q( \* V* A
. R, d6 k7 k  N( |: D. L4 h5 {

  N. }3 g. V: y# ]- l9 Ofunction get($data) {  
7 \% S' _' @, r4 R2 c8 u       $this->data = $data = trim_script($data);  , I; j! s9 @; H+ u& P& ^
       $model_cache = getcache('member_model', 'commons');    N  H2 f0 m8 A3 [* f
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
3 h9 \: a8 |; _       $info = array();  
( \# k6 q. `$ R$ {7 D       $debar_filed = array('catid','title','style','thumb','status','islink','description');  4 z; c+ J) x1 Z3 u- a0 h
       if(is_array($data)) {  
: t, ^, `+ Z2 o$ n) e; }, p           foreach($data as $field=>$value) {  
. T1 `, Y" S/ b- D8 z& S# W7 d              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  3 {, ~0 G. B! Q2 P2 D8 d" t7 B
              $name = $this->fields[$field]['name'];  
% C# Q/ p( E9 S8 t4 P2 s1 Q              $minlength = $this->fields[$field]['minlength'];  3 D5 G2 H7 ?( e4 j" _/ d
              $maxlength = $this->fields[$field]['maxlength'];  
) D& c5 a, _6 q1 _3 y              $pattern = $this->fields[$field]['pattern'];  0 n$ D; Q# {- M' A5 K3 G
              $errortips = $this->fields[$field]['errortips'];  
! P- I. B! t( N) s! ]              if(empty($errortips)) $errortips = "$name 不符合要求!";  7 p" G! @3 ~8 m
              $length = empty($value) ? 0 : strlen($value);  
$ ?2 z6 q; d0 s              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
' d: C# r- i8 c# G" T/ T              if($maxlength && $length > $maxlength && !$isimport) {  9 [  U& O7 @. [5 B' @% ]5 j
                  showmessage("$name 不得超过 $maxlength 个字符!");  
8 z( e7 H# d1 e1 h+ r              } else {  
( l' n9 K+ f  g: d  i# K5 K8 \                  str_cut($value, $maxlength);  
5 t0 h6 V& V2 ?/ B9 P              }  
: A. m* t. z8 o, V( a; w& s0 O              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  $ Y$ M+ ~5 b5 b- u6 f
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
) a5 P6 T& t6 b; W5 a$ a% [              $func = $this->fields[$field]['formtype'];  / n3 ~. _/ B/ E0 }. @& J! S% L
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ! U, y8 F! W* n) i" X
              $info[$field] = $value;  
; ]* R+ H/ Q, x- p, E0 a7 N" h           }  
% b2 V* b- R' P% M6 X       }  
2 i3 o9 a/ O% V$ t       return $info;  
9 b( k7 l" n% H/ i    } . a* p. N+ {* ]; z8 I/ N
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
2 ?( _% L; A" W! ^0 g
6 ?7 v+ M2 m/ J3 e, u再到phpcms\modules\member\index.php 文件account_manage_info函数
0 ]( s" h+ @4 ?9 j' y7 M过了get()函数之后。
% q3 ~, @5 {& E* S/ _% k
4 r2 W9 i9 Q8 |  N1 v/ z/ `( }
: U; ^! m- ~- x* G3 p, {# p$modelinfo = $member_input->get($_POST['info']);  
! r0 M" {; l% J) c* |# H3 X. b           $this->db->set_model($this->memberinfo['modelid']);  
# a8 Z. C! J1 l+ C& X           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
" H3 D0 t4 c0 N0 S  T           if(!empty($membermodelinfo)) {  
% U; ^8 K& [6 [& [              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  / |- c  J+ C" S+ z' k& o6 i
           } else { 1 Y4 j- O+ _  W4 }  b9 d- {, K0 f0 L
直接带入数据库,update函数我们跟进看看
$ K% ^- z* r( o$ t7 P0 b1 I9 T: }$ x( z1 _
, Z3 [' C1 d9 {  ^
public function update($data, $table, $where = '') {  / A4 ~  A  x/ h4 c) k
       if($table == '' or $where == '') {  
% `/ P' }3 f1 t& y* Q5 D           return false;  
$ h. o5 O# `5 M4 ?6 y, t0 v0 x       }  
) x4 ]5 e' j" D       $where = ' WHERE '.$where;  ' P6 g1 E; ?0 O4 t9 z9 _7 C
       $field = '';  
$ K; ?6 q$ H' H4 Q$ y, u       if(is_string($data) && $data != '') {  
$ F; ^* M5 ?4 r1 u) I( O5 b& b           $field = $data;  
2 f* C- u8 U) }" H       } elseif (is_array($data) && count($data) > 0) {  
6 K* {" u2 z+ D2 W4 d+ Z, Y           $fields = array();  
6 e/ p( ^  V2 A% B( `- L           foreach($data as $k=>$v) {  
4 |* x# e3 K( N  k* |$ o              switch (substr($v, 0, 2)) {  
; E" C  ?8 e2 i                  case '+=':  . l5 U+ \% _  _; B) ?
                     $v = substr($v,2);  6 J& V4 F$ e6 A: e2 W) x
                     if (is_numeric($v)) {  
) J! p" z* P4 u: B                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
7 r6 a) U. g) h+ P5 U7 y                     } else {  
2 X' X8 V* Q# ]0 ]) d: \* f                         continue;  
+ ?' B# f+ A1 K3 f) i                     }  ) Z+ q9 s& W- C- n4 x; X$ o
                     break;  
1 q) E4 S# x* ~8 U4 o$ n                  case '-=':    N* j+ J5 n: N
                     $v = substr($v,2);  " N! d3 L6 j8 Y' l
                     if (is_numeric($v)) {  
% E; g7 k# `: M                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
' d$ P; n& B9 h( r                     } else {  
+ w" o* m4 |+ W5 r4 r5 c( |                         continue;  
. \9 x4 D8 N! w) m- {                     }  1 ~3 D9 s# Q* I& I
                     break;  
  }3 h4 R# ~; o( A4 U                  default:  
4 B+ M* I* w5 t% A1 y! ^                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  9 c$ G3 _% k; t1 v4 i
              }  
) M/ R7 U! C% ~' t" u4 w& X           }  
" s* q; v8 i( V; t) c           $field = implode(',', $fields);  7 o: D& n% w( b4 `  r0 ?% X
       } else {  
7 w- n- ~% Y: k/ D. B           return false;  ' K5 m) Y; @6 B
       }  
9 }/ ^6 n' p4 v" T1 y5 Y       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  - X# h/ p8 P, @  a/ H! `/ `
       print_r($sql);  
0 G7 E7 r, s$ N% ~       return $this->execute($sql);  
" L. p: Q( v: \, P+ D( s0 N% t# S    }
3 C- K' c; g$ A- K/ v) q8 E) d( q从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。- `% U, C/ D# O. p! C
" m( _  X3 e/ K  w% C, Z
攻击测试:3 q( ]) U; o5 u& ~
测试地址http://localhost2 K9 H2 {' Y0 x
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句, B+ C, z% _# D3 @! ?! D

1 ~  y3 j: K) Z+ I5 v% H0 Z3 p3 r
: Z, [3 X/ y/ V! r1 L/ ?/ n6 C6 ~  z$ D. l( w7 R) v4 V' d1 }
6 l- W5 H' V8 c& v5 @' ^" s0 _

' J- r; A  N. N3 s

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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