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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告! ~' C2 w# [& l
漏洞作者:skysheep2 I; J, G# ~; d* U! s" W
分析作者:Seay% Z0 Q4 u$ r8 F8 M9 M3 q0 L
博客:http://www.cnseay.com/2 M; r' [0 |6 U. C9 b
漏洞分析:
( N  X4 I8 h0 n- v3 M: Z+ o+ E4 F, X  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。# T( P5 d6 U, D

* |: @1 ~/ j# _' F7 }+ U4 z4 m+ R. N2 {# ^1 e! X1 I! \9 t9 k7 c
/ J/ o* ~8 \) M
public function account_manage_info() {  
/ _8 u# j7 P  {- p8 `       if(isset($_POST['dosubmit'])) {  6 V6 Z6 C7 N4 [. l- u* o& p1 y. K
           //更新用户昵称  
4 Z3 H4 b1 t: f& ~           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
) w" h- U, A( e# D           if($nickname) {  
& C; E+ ], I+ }$ T* s! z$ r3 ?6 u              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
3 s- {. `( v6 Q4 k              if(!isset($cookietime)) {  ! v' t1 X6 J1 Y8 u
                  $get_cookietime = param::get_cookie('cookietime');  
* f1 I2 Q, F, ~) Q              }  
6 H" _( f4 t( o" ]$ H9 h% K              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  : I+ m4 g0 c# H8 P, L7 R6 S
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  . A% M3 P- b, i, p  f* ?4 f
              param::set_cookie('_nickname', $nickname, $cookietime);  . m" X7 ~0 {, V- y
           }  0 J6 s8 J" Y* p- ?
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
) v* T: v- c/ ^" T& t- S           require_once CACHE_MODEL_PATH.'member_update.class.php';  
0 o4 x! X# }+ z  N9 a           $member_input = new member_input($this->memberinfo['modelid']);  - c: m; s) w$ u0 U! q
           $modelinfo = $member_input->get($_POST['info']);  
. O6 j6 n) f; l  s  l, q5 ~/ X           $this->db->set_model($this->memberinfo['modelid']);  
3 i, d3 O( ^1 e           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
+ T  `7 n3 g6 M, J+ G           if(!empty($membermodelinfo)) {  
3 x$ E4 K/ q/ Q9 r3 c/ Z              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
0 J) b" ^) }) R8 r, X6 Q! [1 c) a           } else {  
7 H, ]1 o' z) e$ ~6 k1 {              $modelinfo['userid'] = $this->memberinfo['userid'];  1 {0 o1 D; O0 k5 ^
              $this->db->insert($modelinfo);  
% F1 R* A" q' Z9 S0 `5 d           }
. g( x- k# f; y代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,9 H1 x0 B3 X1 S# b# Q% K! l
在\caches\caches_model\caches_data\ member_input.class.php 文件中:4 T! ~; y* Q- S4 Z

1 b  Q- P: M* G3 U( V" N+ @$ b6 S% t* _' |
  \/ ?) I; `7 w- y
function get($data) {  
8 m  Z5 w9 f, M3 n' d       $this->data = $data = trim_script($data);  $ w5 A6 i$ _$ J. W* F
       $model_cache = getcache('member_model', 'commons');  + ^/ E4 V; ^. G8 X' }; z
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  6 q8 b% W0 [' a  q! ]1 l. J
       $info = array();  3 }$ e% @0 x, p
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
. L% I' [7 c- s8 j% t& P2 C       if(is_array($data)) {  1 M  S" g( W% F" U' s
           foreach($data as $field=>$value) {  4 Y; x4 v3 `! T( u
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  & J6 X$ a9 h4 }  m. E4 J
              $name = $this->fields[$field]['name'];  
/ f% V5 S- O4 x+ e              $minlength = $this->fields[$field]['minlength'];  
: r: `% j( F- ^4 Z              $maxlength = $this->fields[$field]['maxlength'];  3 q% ^8 Q, }* K- D* j- U
              $pattern = $this->fields[$field]['pattern'];  
' `: y$ G. c: b2 v( t' j; i# S1 |              $errortips = $this->fields[$field]['errortips'];  
) K' s# e  A! s- Y( Q$ t. L              if(empty($errortips)) $errortips = "$name 不符合要求!";  
) }! Q2 U% o* e              $length = empty($value) ? 0 : strlen($value);    \& |( R; z+ x: J
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  2 c- |" V( e2 X' ^
              if($maxlength && $length > $maxlength && !$isimport) {  
/ r: K% R4 v$ I, Q3 |0 C                  showmessage("$name 不得超过 $maxlength 个字符!");  ) T& w, K' P9 S
              } else {  
. C5 ^2 X& I) G# h  j( n: Z                  str_cut($value, $maxlength);  
$ [$ s+ ~4 j- u& `1 }              }  
; X# G/ U3 V- O1 K: A: J/ [# \0 V              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
9 x* a  k3 _3 N8 P$ n  `2 k; u                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
' T3 {, i9 y. J) z              $func = $this->fields[$field]['formtype'];  
: z& n/ q" }  D              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
: K# b' v9 Y, y, x8 ?/ W9 I, @              $info[$field] = $value;  8 W% B/ a2 Z, n( a
           }  0 x. v8 V% \* t
       }  ( f5 U( u7 J$ I
       return $info;  
; p6 E8 y& j4 j; _" y3 i) G    }
2 E; k/ {# K6 O' F% K' H  xtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
; I& s7 D' v# r1 ^; Q, a8 i" O) \) X" V6 h  h
再到phpcms\modules\member\index.php 文件account_manage_info函数7 ]8 F% a& n+ ^7 T) ?* w' l
过了get()函数之后。
4 P0 r5 S6 ]- X* M) \& @/ ^& k) q- {, r7 H8 H. k2 C/ E& b

6 Q6 d( ^# _9 j6 y! x# ?" o$modelinfo = $member_input->get($_POST['info']);  4 d* ~  H" o- e. q
           $this->db->set_model($this->memberinfo['modelid']);  
& A; e8 t* U& @# h           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
% Q" H! o8 {  o           if(!empty($membermodelinfo)) {  
  F2 j: p1 |/ ?7 q7 z8 C. f              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  " V4 f  o7 p, n/ o( D5 j2 K2 p. ]
           } else { 2 O9 ]+ }. ^: d6 N" W
直接带入数据库,update函数我们跟进看看
0 u9 i0 O, l7 l5 c9 W* |. y: R& _; ^0 v! |/ Q$ h) W" C) i2 _; e& L, T% j
. z2 ^9 |; n$ h( {
public function update($data, $table, $where = '') {  
7 ~, \( w- S! i0 D. b: p+ R1 P0 u& ~       if($table == '' or $where == '') {  
6 }$ t' N4 H, }' G4 X8 Y$ C6 Z           return false;  
" W! ^$ V$ \3 d: O7 B. U; F       }  8 c2 w' H2 W8 S- y# q: i7 k' ~
       $where = ' WHERE '.$where;  
$ M- S' S& o& M       $field = '';  4 T( C0 r" X1 i1 C2 G$ }- a
       if(is_string($data) && $data != '') {  
6 Q% y9 D) D. f: Q" ?- ]/ ]4 R+ @4 ?           $field = $data;  ) \$ b$ F+ N4 @2 k% S, L3 E9 W
       } elseif (is_array($data) && count($data) > 0) {    ~3 a7 O3 Z# i! n5 K1 I- C
           $fields = array();  
6 K, \# T! {, K) G$ @7 v7 x           foreach($data as $k=>$v) {  # h2 f# f& U$ |) V) ^3 Y: a7 h
              switch (substr($v, 0, 2)) {  4 U9 U; u4 T/ G7 c6 U  w: y7 }
                  case '+=':  
+ @0 h, n1 g" c                     $v = substr($v,2);  9 J5 @" i* F9 \. h0 Y* j
                     if (is_numeric($v)) {  ' y) }% R  |  I8 @4 G1 {- [* W
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  $ j% |) j: u0 B
                     } else {  
( P0 v) I& Z- q+ W& y5 g                         continue;  3 F' n9 ^5 G& e  N: I
                     }  
1 q8 D! x  }6 r; C7 |                     break;  
5 a# T4 ?0 e$ r  [8 H" A3 N9 P                  case '-=':  ' ^9 ]4 g* B* C4 P" ^6 p
                     $v = substr($v,2);  
" t- W8 u9 |: J/ P' I; Y                     if (is_numeric($v)) {  : [1 D: d" q; e; S. b
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  2 C! q5 A) W: h" `- K
                     } else {  * }% Y: J" ?% @! b- j3 p
                         continue;  
* l2 H1 `7 s& O1 m                     }  ' {3 q! X  _: V* q; \5 F( Q
                     break;  ! O' a/ t# f8 _8 d( S
                  default:  
+ c1 _3 |8 A, Z& L3 M                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
; n0 s2 j# F* m9 F# b% e1 P3 c              }  
8 T5 S4 E' j9 {" w4 M           }  
0 L( T  w% U+ M7 w' O9 h           $field = implode(',', $fields);  , F0 E: ~. _' e6 Q( t4 q9 Y" `
       } else {  
- z% P0 I9 V' \5 l, Y# D% Q$ ~& S           return false;  
- h% E( i. S6 s4 i       }  
; E3 x- H: i% \$ m" ^: A7 V; E       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
# |: @2 Z  J5 M% t6 c3 Y6 ]       print_r($sql);  
. U- \1 ?2 g* I; L6 O0 W0 c( y       return $this->execute($sql);  & V% {& N. X. j* @, f
    }
4 N: v* l  s5 M- c2 T; l# x4 C/ Y从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
6 K5 I9 r0 m7 u. }5 J
' B5 Z7 @3 p% B! i- V攻击测试:4 K6 w0 Z! p2 M1 T7 d8 o+ u
测试地址http://localhost
' m$ ^2 ^# I7 Z* L8 K2 K  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
6 H( D/ p9 g" t7 R' B
6 b" s  V# w4 D% p5 U. |6 G6 \ 4 }8 f7 f# I3 W- U& C3 y7 K; o

9 R3 `& {2 |! U, _# k( v& }
2 A# d2 j7 k% L5 p- i0 V1 [* D; f' ~

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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