找回密码
 立即注册
查看: 2552|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告+ `2 S8 J* A; h+ x2 g
漏洞作者:skysheep
! {% g2 t0 _* r3 F8 f! T, H分析作者:Seay
& C, l0 k$ E  {' e博客:http://www.cnseay.com/
' r" y8 o1 g" \# L漏洞分析:
+ X2 s& z5 u' i  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。# S$ q, J4 Q8 y6 d2 U" Q$ [8 a! T0 _

' ]3 Z4 n* E! d# y/ V* Q$ O
0 R; [' M6 m0 Z: D' F- l/ j 9 O" a$ F- j, s; M* a+ V; j
public function account_manage_info() {  
7 b( c" q5 x! H& |  o% C       if(isset($_POST['dosubmit'])) {  
# v# J8 b' F( g& x* F2 N- M6 \           //更新用户昵称  
% _# G& {1 i, `. u& _           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  : r/ j1 i$ t/ s+ Y5 q# a0 d' C8 l% ?
           if($nickname) {  . M% H  ~9 z, R# M, Q8 q/ g* K: L
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
7 R5 S6 p  F* m4 e. a              if(!isset($cookietime)) {  1 }; S! i" E" g2 H1 F; `6 z5 q0 t
                  $get_cookietime = param::get_cookie('cookietime');  
  I# W# h# z8 D7 E              }  + {' I/ V- i7 U6 l7 ^$ I
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
. g, ?  A+ {. F, M+ r& y8 B1 Y              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
! A6 Q: ^3 }5 \              param::set_cookie('_nickname', $nickname, $cookietime);  - |' f+ I+ y+ [4 N  k
           }  
1 @: p$ f  I$ }% X# n/ h  l           require_once CACHE_MODEL_PATH.'member_input.class.php';  
& O. Z8 `" U  P/ }& P; X+ ]           require_once CACHE_MODEL_PATH.'member_update.class.php';  
. k: r# D+ D# ]+ y7 d! E/ a           $member_input = new member_input($this->memberinfo['modelid']);  
; e& R4 Q1 o9 i2 d           $modelinfo = $member_input->get($_POST['info']);  + o( b$ c2 t+ P! G) z
           $this->db->set_model($this->memberinfo['modelid']);  
; y4 z# T  V' ]  P4 T           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
) s% O! Q6 z9 b6 k; @           if(!empty($membermodelinfo)) {  
" m) u7 z# S( m+ ]# C9 L# V              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
2 J, ~5 Q% Y* @7 O! m           } else {  
# g9 O7 i/ W5 l+ @7 ?              $modelinfo['userid'] = $this->memberinfo['userid'];  ( X, a. R5 ?* Y" z, r/ Z4 r
              $this->db->insert($modelinfo);  
! Z3 u" T; i, X9 [, v           }
! T) O3 ]6 y! M& `( z2 b* r/ F代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
& [7 A/ T0 T) I$ `在\caches\caches_model\caches_data\ member_input.class.php 文件中:$ M  U# ?+ h: D2 [3 c
, n! ]6 ~. I% R! v9 N; t
" n. O( B8 k0 y! S+ X4 q; V
" v& T' |( Y4 N: g4 L
function get($data) {  9 L2 ~! f, @1 S: [) G
       $this->data = $data = trim_script($data);  ' K# }) L0 }. G3 o6 P: I# c+ Y+ x
       $model_cache = getcache('member_model', 'commons');  
2 J. S" C' R) e! }- |8 P       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
7 z- i6 y( `9 d  ?       $info = array();  
1 b8 `1 I' X- t5 |  H       $debar_filed = array('catid','title','style','thumb','status','islink','description');  * e4 Z# M6 {4 T1 Z
       if(is_array($data)) {  
/ T4 m9 {. ^! L0 F% W           foreach($data as $field=>$value) {  6 B& Q, Y7 \% @' t. r
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ) e% ?" R8 w6 f; F$ C8 I# b9 o
              $name = $this->fields[$field]['name'];  ( j6 H  ^( j1 @; }, i0 G0 p4 K0 {
              $minlength = $this->fields[$field]['minlength'];  
: p/ o6 r7 m& j3 q              $maxlength = $this->fields[$field]['maxlength'];  
( c/ J- Y7 j, F0 [7 H- @              $pattern = $this->fields[$field]['pattern'];  / Q6 b7 L, \) q6 @" }6 E- T8 \
              $errortips = $this->fields[$field]['errortips'];  
3 f/ C8 c# P: K1 @' V- K0 k              if(empty($errortips)) $errortips = "$name 不符合要求!";  
- ~, c/ n) [, r/ Y3 P2 ]5 `4 E              $length = empty($value) ? 0 : strlen($value);  
2 Q0 ?# o' s2 r5 f& D; O2 h% @              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
6 Y- _- x4 Z2 F1 l' Y              if($maxlength && $length > $maxlength && !$isimport) {  % y4 z$ \3 P& E7 e
                  showmessage("$name 不得超过 $maxlength 个字符!");  . J+ K: ?- b9 h. T! O
              } else {  
8 [( B3 r+ Y5 T; k                  str_cut($value, $maxlength);  : E) `. g( r8 ~* ^3 p: U" h3 y
              }  ( C) X! k1 ^  `& |
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
7 @* P- m, a0 N' A% N7 H+ B- o                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
& B! s( j1 [" p/ j9 ?5 k              $func = $this->fields[$field]['formtype'];  
. F3 V1 R& x/ i' r, |' L              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
, n& C8 `' m4 {* e% r              $info[$field] = $value;  
; n7 N, e: Y$ W0 n3 g) G           }  
2 u0 T! g/ |, r       }  
" A6 s( N1 z) A4 h- F: F4 K4 z       return $info;  
. s% B2 C9 ?4 U6 Y4 N+ q    }
$ {3 e  u5 h, Q! i4 Itrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
3 g% r. x8 q% M- p# t: X" J
0 J' j  d: O$ A% {  S再到phpcms\modules\member\index.php 文件account_manage_info函数
! S+ ^/ u0 w$ K# f过了get()函数之后。0 Q/ m3 S& I1 [  C
# p, D1 O) E% T1 E' z
% r5 e" l. ~0 y& v1 C" |7 y
$modelinfo = $member_input->get($_POST['info']);  
/ x. R. p1 l& u- h6 U8 @8 l. l           $this->db->set_model($this->memberinfo['modelid']);  
8 \0 ?+ i2 `8 M7 g+ O# C0 b           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  % i! C1 j0 z  H' {
           if(!empty($membermodelinfo)) {  
% `) {) t- t& E+ M$ y) S, S              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
4 h( [. p* V, l- P9 B* X           } else { ' E4 Z# e0 s& E9 }
直接带入数据库,update函数我们跟进看看
& r3 }2 w2 ?- }8 f. w* I0 r3 r6 u; M' U  h" |( G
! D) k( b6 P" b0 }
public function update($data, $table, $where = '') {  
9 _* I: |7 Q6 w5 ]       if($table == '' or $where == '') {  
* }7 G; [+ E% R4 h( s- j           return false;  
/ L# D( L* E. z" e       }  - p( T: X* k- `: r( ~8 c! A  B0 p
       $where = ' WHERE '.$where;  
5 F2 C: r. K; V, V- p       $field = '';  
6 ~! P9 i, h+ s' Y$ W       if(is_string($data) && $data != '') {  
0 C8 h4 c' T- J  ]5 G' V2 S& q           $field = $data;  
; {8 s' Y; H* G; u0 ?$ Z       } elseif (is_array($data) && count($data) > 0) {  
5 w* O- r$ l4 F6 |           $fields = array();  : A+ R# u5 V8 [
           foreach($data as $k=>$v) {  # M4 |& d, {7 s- V0 ~! U  [% O( f# M# _
              switch (substr($v, 0, 2)) {  
) Z$ V/ s: E+ F& r                  case '+=':  
8 X$ B3 c* I2 v4 n. g3 S                     $v = substr($v,2);  + E5 |) j+ R# i5 ?$ P
                     if (is_numeric($v)) {  
, K& f" b( I; A. v                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
! L- j% B1 s) g1 G2 v# w                     } else {  7 L6 c) O1 C* z- Y) q* P. c
                         continue;  - J0 E( V; ^: W0 T/ ~2 T& ^7 z; X
                     }  
0 |, D+ K: O) E+ Y7 F                     break;  5 Q3 i/ R- }* ^
                  case '-=':  ( ?( e( {6 r- v& X' a) v9 V
                     $v = substr($v,2);  
1 T% {1 l6 E0 f7 ?                     if (is_numeric($v)) {  ) h4 c  V. m) V
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
$ F) ^: Z. _; ?, d) t' c                     } else {  
# u9 N% {7 @. q! n                         continue;  
) b- U& e3 d- \% h& V                     }  
5 z1 r8 P1 i* @0 ]                     break;  0 P4 M8 U3 W' S1 ^, W& S9 L
                  default:  
' ]8 K! o7 R: E6 q2 @: x0 ]                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
  {8 G( H  w3 z. o/ v1 X) m              }  
2 U6 e! i. e( x& C# E: Z           }  
9 G8 W0 _0 c6 y  v: L           $field = implode(',', $fields);  8 U8 j" e' G9 O  A3 `' Z: b1 A
       } else {  
* l# [9 S6 y4 B, V! g           return false;  - }6 F- f. L" t$ ~- C% {+ l) C! F1 e
       }  
6 O( Y3 ?. W) E7 }1 H' }       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
' F) M0 G; B; c       print_r($sql);  * Q4 n7 B- b+ A
       return $this->execute($sql);  
5 g) j) b7 t) X2 |$ ?9 M    } ) q# P8 J3 A4 R6 j) D3 L# l
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ f, o6 @1 H" p& X1 [
2 \  I( z5 e; Y攻击测试:  W& \6 [5 |, p9 a
测试地址http://localhost* _/ w7 l% d6 \* Z/ }4 u
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句! m7 R% H* \) W0 m1 }
0 Y5 }! l( o( [
  ]% X  x  k0 p/ Z1 w$ {) |

9 V3 {9 m, o5 D: P5 M
8 o$ u" c/ s5 ~! N: v; C9 s  m2 E# M% T8 C- C; g* [, |7 E

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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