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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告' }5 B3 J; A1 \1 u
漏洞作者:skysheep
8 U( ^: s9 k! x. E: i; V分析作者:Seay
3 d/ O( m% m- u7 h5 Q) a% f& Z博客:http://www.cnseay.com/
2 L) j4 N5 B1 h5 z% M/ l$ x漏洞分析:( ~. X; l( u  L  Z' S! p1 j* s6 \
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。" l& D0 i" O  j% }

( M4 s" j; e* o+ x0 N: c: _1 g- G- z1 z$ N& {, [) f

: F! M7 T/ \# Tpublic function account_manage_info() {  ( G: u8 y- ^5 A+ c$ z+ c( V- y" l# f
       if(isset($_POST['dosubmit'])) {  8 p' {! B/ @/ G3 c% h2 J  y/ y
           //更新用户昵称  
; ]- f0 t8 d& r6 ?. ?& G7 z           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
9 E9 ^6 T1 J5 W* _9 W/ {           if($nickname) {  # ~% E0 l: ^, T! f9 {! c
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  # G! _; s$ m6 @
              if(!isset($cookietime)) {  & r2 E( Q3 Q/ D) Q
                  $get_cookietime = param::get_cookie('cookietime');  
# T3 J6 Q2 T  I2 S4 _% H. d              }  
1 D, h$ v2 a2 V              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  * j1 Z9 \% H3 i& ^( C( s( b
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  " m) i* `. [# M; B; Q: f: z5 d' f$ M
              param::set_cookie('_nickname', $nickname, $cookietime);  
- G# C5 Q) X0 [' E. e           }  
; r0 `+ ?( s; W6 C; V           require_once CACHE_MODEL_PATH.'member_input.class.php';  
* W; j( y  |0 v1 J( m9 ^  f           require_once CACHE_MODEL_PATH.'member_update.class.php';  
6 @+ s6 b  \' U: k3 r           $member_input = new member_input($this->memberinfo['modelid']);  
. R9 x# {, Z4 K5 {& ]. |           $modelinfo = $member_input->get($_POST['info']);  
! E0 D3 z1 x4 ~0 v/ Q( H8 j1 G3 J. b           $this->db->set_model($this->memberinfo['modelid']);  
8 c  y7 q# N7 s           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
6 {# X4 N1 F9 P- C           if(!empty($membermodelinfo)) {  " C( [: I1 g( O' \) m5 Q
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; `( z& K' L/ W% d' P/ T; r; p, q
           } else {  
' _1 ^$ p* X9 w% g, v              $modelinfo['userid'] = $this->memberinfo['userid'];  
/ U- B* ]! \1 v              $this->db->insert($modelinfo);  
1 R* f$ o' S" u  ~+ I           }
: L, ^- _: }  `/ D4 y0 K1 V代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,! p" B! h( \/ R3 x
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
9 v# R) _& [" S$ `$ A6 F% O0 w! C/ {' ~5 B- p- U1 ^, K
1 J' I, f! v2 z8 Y2 e9 T3 E
- I8 E& q% _9 S/ v! Q  y4 `
function get($data) {  
7 q( c. ^: c# n7 Z       $this->data = $data = trim_script($data);  
8 V: i) t! K8 L2 `( p1 S       $model_cache = getcache('member_model', 'commons');  - \7 }5 {* D( E1 |/ ^& t
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
1 f3 c% M9 Q0 h4 m  B       $info = array();  ( f* O* R, D0 I- M
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  6 V' M5 A7 n8 O) t8 O4 p& s
       if(is_array($data)) {  ! `; }1 y8 r( o9 a& d" |4 `
           foreach($data as $field=>$value) {  % o) g" W/ |3 |. F9 s; K
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  % q0 N- P3 s' U
              $name = $this->fields[$field]['name'];  & C+ X, K% D' ?6 J- [  g* `" }
              $minlength = $this->fields[$field]['minlength'];  - I6 c' _' j9 W5 _
              $maxlength = $this->fields[$field]['maxlength'];  ; M5 W8 |8 d6 L9 n
              $pattern = $this->fields[$field]['pattern'];  5 B# i/ I- e, S+ K. f$ n
              $errortips = $this->fields[$field]['errortips'];  
& H; W& I$ N8 D' G& B8 L$ U7 K              if(empty($errortips)) $errortips = "$name 不符合要求!";  
# P2 Q# a  f/ j              $length = empty($value) ? 0 : strlen($value);  
8 w9 O* H+ o/ V6 {) A              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
7 z8 f0 e" ~! s1 O2 ?: t$ l6 z$ T              if($maxlength && $length > $maxlength && !$isimport) {  
3 _3 g  Q3 \$ ?% q  H# u  w                  showmessage("$name 不得超过 $maxlength 个字符!");  
5 v4 C, R/ P# w# S7 n- ?              } else {  
, J1 A( j& \* Z5 y) z# O                  str_cut($value, $maxlength);  " Y  b6 a# _8 p, k: R
              }  - X4 Y2 N- n+ N, z9 J& j4 D
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  * B. u; M: Y; o9 E0 s% b
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ( A1 o, o8 {! g
              $func = $this->fields[$field]['formtype'];  - J- ^) m; t/ L( O
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
9 y; S* }5 g1 o, x( ~3 R0 ]              $info[$field] = $value;  
6 t# J/ T+ T' t: D           }  
6 _3 {) [: ]8 Q0 w       }  
" D7 U# u7 M4 t: W+ c. M       return $info;  
1 e" T( F0 z6 q    }
" B+ f5 p+ q$ N* [; D6 B) A9 utrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
5 ^. n3 m3 \: |6 W" j. B0 E; ~6 X
再到phpcms\modules\member\index.php 文件account_manage_info函数1 s# \0 |& U% A  d' _, N! F$ R  j
过了get()函数之后。8 ?; g- s# z9 t
- z" Z  y- l  q$ r
3 n- K6 G' V% m: x5 z3 ~2 S0 t; G4 i. S
$modelinfo = $member_input->get($_POST['info']);  / W' {* ?6 f5 q' u, s4 d
           $this->db->set_model($this->memberinfo['modelid']);  9 k6 {: P& f* t( g2 G, g$ z
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 K  b7 ~2 p2 C( S7 t$ e- Z
           if(!empty($membermodelinfo)) {  
$ R* h2 L$ F/ r$ O              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  # F! G& T' a2 F: j' P8 y; Z# f
           } else {
9 B% d( C4 L" Z. V* V7 J直接带入数据库,update函数我们跟进看看
; |+ f9 ~, d8 @# R​& {1 O+ z# e4 ?0 g9 r
+ {9 v8 c4 D. s8 i
public function update($data, $table, $where = '') {  - I, a; N7 s! w' `3 N
       if($table == '' or $where == '') {  + p  j# K8 n2 J4 X7 \3 s
           return false;  
* t3 W0 E9 @5 y3 o6 p% }$ L8 H       }  
  ]7 [8 y: V) G6 K5 `$ `       $where = ' WHERE '.$where;  
. K2 I4 |  u  U# c       $field = '';  
0 s7 X' v" \! r$ y# {       if(is_string($data) && $data != '') {  
& w4 L, B- X& S2 Z; }  ^$ h$ @           $field = $data;  
7 a, y; Z  B9 a( s       } elseif (is_array($data) && count($data) > 0) {  
0 W+ N# z& }) X$ G: q1 q: B- |           $fields = array();  ! ]- i. [- v4 p% ]6 Z2 h/ o
           foreach($data as $k=>$v) {  2 H& k2 C! D7 a8 b9 y
              switch (substr($v, 0, 2)) {  - Z+ I) B$ |- B
                  case '+=':  
, W/ O2 h& X4 H( _; A) W& {                     $v = substr($v,2);  
5 Z5 U8 Y. b! u# X6 O                     if (is_numeric($v)) {  
; ]3 o: y$ J) F6 ~% O3 P% i" U" I                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  # M- f1 p# }& O8 f& J
                     } else {  
' U" F9 c, C+ r+ d4 @                         continue;  $ ]  T/ h: ~* L% Z% j4 A( Q: I+ X
                     }  , M' h: {8 {* I! L2 u! E& G$ u3 p
                     break;  1 e1 l/ _) J! k$ f3 s
                  case '-=':  
# d+ W; j4 a" A. w2 L; [; x8 F                     $v = substr($v,2);  4 a2 t6 o8 `- @2 Q# H( i
                     if (is_numeric($v)) {  
, Y0 E& A# [. y, I+ j* W                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
4 `, ^' V8 ?" P  M                     } else {  
2 Y5 ]  X3 |7 K9 ^, N$ X6 W+ Z                         continue;  2 Q) B2 w( t- H$ Z3 J
                     }  $ [2 [" A. m( r& D
                     break;  $ a' V9 F& b! a- q! M
                  default:  0 Z  u% ?' I/ i, p
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
* A3 V. y% o3 ?- E& |              }  % f( p+ k/ k: Z! p. u) r: ~, h5 F
           }  8 _+ |2 i, h3 I3 I/ G% t
           $field = implode(',', $fields);  
9 [3 ~) F+ N+ a$ Q4 m8 Q* U& p' d1 v       } else {    L+ \- ?1 E: }3 g0 R7 `8 i( g
           return false;  
' |: P' o: q: w# m       }  
5 E  |+ w  ?# H* G: A) o) B       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
7 w. z) M% n4 c! {       print_r($sql);  
  B8 w; G& ?( |/ g! {' B       return $this->execute($sql);  
8 f3 p& f8 |* [    } - @3 u" W% ?$ G3 m; |+ j& z& e
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
7 a6 z2 r, H3 C  {2 Y
5 Z# t1 i8 s" m; e攻击测试:
, W5 O: H# I0 ]- I# A测试地址http://localhost
9 Q" a4 n1 ~2 h  t  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句( ]/ A4 q  e% \" f( j/ t5 S! [# y

, O* _& C/ r( `0 T1 F2 q( n; e
9 J3 q! a5 q, ~! f+ p: j4 ~* ~% x: B: }$ I5 ^

' p$ u9 Y( K9 a- e& m6 n6 Q" X4 u7 {8 w: {9 ^5 g! g

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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