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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
, L* c( C' E" V  G漏洞作者:skysheep
$ Q- M- `' x0 W" y% s; _分析作者:Seay
% J: Y. w) ?% {$ e博客:http://www.cnseay.com/
2 x7 r) Z( n- u  _# {( w漏洞分析:& @" Q) V: t. v
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
0 g& q2 ]0 W' q" `$ F" O: J! U5 l! v3 p) H2 R4 O

: l' M6 a  p9 I8 Q2 M
* U: I" K6 e% z9 Y# bpublic function account_manage_info() {  5 L$ Z  h& J( x
       if(isset($_POST['dosubmit'])) {  4 u) d$ p8 K, E8 {
           //更新用户昵称  
, ~" I( ~, \3 J. j           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
  }9 |  p( H$ J. G           if($nickname) {  
3 V# y4 Y& k3 E$ l  v+ ?; E7 f! d              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  - H, c! W0 r9 p% g% [, L
              if(!isset($cookietime)) {  $ }; Y3 w* ^( m* Y2 h$ I, b
                  $get_cookietime = param::get_cookie('cookietime');  
7 q, c9 j4 I% q6 X$ r2 I8 r              }  " @" l) O5 E' S+ }
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
4 L  A2 ]$ s) n! K              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
6 H) P' k7 c% |3 U              param::set_cookie('_nickname', $nickname, $cookietime);  / E( `& g( a5 l+ L4 l6 u# }+ n& C
           }  
8 v0 o$ y# C0 `1 W" w3 m( D           require_once CACHE_MODEL_PATH.'member_input.class.php';  ; \$ q9 |7 a0 A$ l
           require_once CACHE_MODEL_PATH.'member_update.class.php';  ' t/ w/ ?, Q8 k0 A8 p
           $member_input = new member_input($this->memberinfo['modelid']);  
3 ]( @$ b- B6 s+ j( @           $modelinfo = $member_input->get($_POST['info']);  8 Z) w  C" |( S) B/ m& R& I
           $this->db->set_model($this->memberinfo['modelid']);  
2 }; _4 i/ Z8 @6 @" R. r           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
; u0 M  V) h4 \; B! v2 h( x0 L           if(!empty($membermodelinfo)) {  " S4 W  V! Q! T) Q8 l
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
7 c; O/ T1 [& d9 C           } else {  
0 z8 y' C! W- z* q4 X4 O1 f" M              $modelinfo['userid'] = $this->memberinfo['userid'];  0 e+ Q+ V; c" x: `
              $this->db->insert($modelinfo);  
+ K. A, R5 Z4 w           }
3 r+ `* m5 Q6 r0 ~! [代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,) P) `  x% M7 `
在\caches\caches_model\caches_data\ member_input.class.php 文件中:) b9 L7 D/ D  S$ }/ W1 ^

+ x6 m) x3 C1 M# Z/ V2 `8 o7 B7 c, w; f/ l- F( v( s' I( \
+ p) n0 h" _( F- ~* t! s1 V. \
function get($data) {  
$ i5 y; \* ^: g- U5 f$ ~       $this->data = $data = trim_script($data);  
, C3 D: g, @( s( S$ P       $model_cache = getcache('member_model', 'commons');  
- n& a' d, A% }: ^8 |( t5 r       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  4 {7 j* u1 {, Z) R5 }; Q  L+ _
       $info = array();  
/ U% s7 \& ?8 ^$ w( i5 t       $debar_filed = array('catid','title','style','thumb','status','islink','description');  7 l" O; g) [* e8 R  t
       if(is_array($data)) {  
$ a, l& }( X; o& V- L& F7 _           foreach($data as $field=>$value) {  
0 G* K8 v# O) D$ J1 k  I$ O              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  4 V1 k7 x: N4 h
              $name = $this->fields[$field]['name'];  9 c$ [; U) Y2 X9 R5 y$ r( @
              $minlength = $this->fields[$field]['minlength'];  
+ O: `7 z1 d- H! u8 W' @              $maxlength = $this->fields[$field]['maxlength'];  1 s. R% e+ L3 j/ T2 J
              $pattern = $this->fields[$field]['pattern'];  / U! t6 L6 Q9 d4 Z0 t
              $errortips = $this->fields[$field]['errortips'];  5 ?" Y0 b! }% J/ w: l, Y
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
6 G. e" J7 w! c1 Z( ^              $length = empty($value) ? 0 : strlen($value);  
7 j  R6 M' O& p- t7 i. l1 D3 G              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
7 o/ @# c: c4 Z8 G, w. h" m8 m              if($maxlength && $length > $maxlength && !$isimport) {  ) z$ C5 L2 U7 q+ N% n8 ~
                  showmessage("$name 不得超过 $maxlength 个字符!");  + a  F6 h+ M2 T) D
              } else {  # i/ C$ Q( A% B- g( [, o, u
                  str_cut($value, $maxlength);  6 z$ ^% n- s$ J! ~, N1 x
              }  7 M4 Q, }8 E" |
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
+ n% M% {6 W9 }  g/ o/ [" q! x& w% \                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
0 ~; p9 T6 q4 N& M! P3 y/ n              $func = $this->fields[$field]['formtype'];  
3 a. c( s4 L9 x1 p. [8 @              if(method_exists($this, $func)) $value = $this->$func($field, $value);  8 U2 c7 D* L2 Y- y- l3 B! j- R" {6 ?
              $info[$field] = $value;  
( i$ U* R2 Z( B( j           }  . V* D+ h& i7 j0 y) |- K6 p( b
       }  
0 K; B' _+ l5 Q       return $info;  6 o- x. e) z0 o& N1 g0 W" @* U# ^/ _: [
    }
8 r$ Z! B7 Z- ~: itrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,' R! D2 q% W  J2 }3 a

- C2 x. `  }  m! @$ s, r; ~" a再到phpcms\modules\member\index.php 文件account_manage_info函数; [: S: l$ H' D: l
过了get()函数之后。1 F2 ^7 |2 A: V8 X/ E' e

  q. G% C8 B5 H5 L1 V5 S
: k6 V9 Q8 n3 f- Z0 y0 J% L$modelinfo = $member_input->get($_POST['info']);  0 h$ @- r1 I# F, q  S- s
           $this->db->set_model($this->memberinfo['modelid']);  $ @' D- d+ U, v9 v
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  2 @; l1 b# ]5 f) F
           if(!empty($membermodelinfo)) {  
: y6 u6 v8 V( a! o  u) f% h6 h              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  8 ]) ~; H& g% x5 G# ~  m/ M3 ^
           } else {
5 u& L8 G. ^* d7 A' E2 q0 u9 b直接带入数据库,update函数我们跟进看看
! T4 v  k* _2 g# P) d8 v7 p. @6 j
; R; b# E; I2 O) j0 U) Y : t/ U0 u8 q  f4 \. B  m
public function update($data, $table, $where = '') {  ( v! M0 K6 ^4 M: w
       if($table == '' or $where == '') {  
# W% _, f7 O2 O8 l% q$ n+ F* ~           return false;  
( c& G" J  }/ o8 X, c8 i! ~       }  7 f5 t& h" p! j! h
       $where = ' WHERE '.$where;  1 |* }1 J& u8 `8 Y6 {* |
       $field = '';  
- _, }5 Y; B& I       if(is_string($data) && $data != '') {  3 n& y7 e- W# ~
           $field = $data;  
* j4 J  w7 q# z2 Z0 \1 [6 T       } elseif (is_array($data) && count($data) > 0) {  & _8 m0 k# p  @  z7 D
           $fields = array();  
* R) C* ?& Y( p1 o% b( y; f           foreach($data as $k=>$v) {  3 F" }+ p& o5 `+ T5 w
              switch (substr($v, 0, 2)) {  # P& y" u6 G- U
                  case '+=':  
& v- U5 {5 k, w6 ]" o& |# l                     $v = substr($v,2);  
' @5 l* u0 u1 m$ y# [7 g' N# }                     if (is_numeric($v)) {  3 x' ~% E+ m4 I& f" H
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
- V8 b) n3 N/ i$ I' x. i                     } else {  
. d5 V; v) b0 z& A7 L! Y                         continue;  
$ n( z# a' a2 k) k                     }  8 Q: K* {4 F4 ^: z0 U, ~: V
                     break;  / Z" i$ l! o6 c3 d) G# C6 B
                  case '-=':  
4 o8 n- M  H7 ^3 Z1 {# d0 R                     $v = substr($v,2);  
: N* {7 Z3 N, K! g! N8 i                     if (is_numeric($v)) {  ( @) B9 f$ {1 I' K% v
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
4 b7 g  e0 K# n5 [! j                     } else {  
$ Q: ]5 l5 o. y  c# w- R& R                         continue;  
+ j, f( Z3 C6 F                     }  
' c! J2 M# @3 N( e/ S% U* u6 ^8 ]                     break;  
. n" U) @0 O4 w5 U. q                  default:  
  j7 ]9 S8 i7 o# L                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
: b8 m, A( W9 ^% }              }  
% x- i' D: [& Q* j3 _6 l, l+ R           }  / j1 C3 f+ t" a( y
           $field = implode(',', $fields);  % y- S, @2 X% E: G' |8 k; y' M
       } else {  
4 X  O* T" A+ J( K           return false;  1 f: U6 {# N! R7 |
       }  
7 v, Y4 w: E9 G8 i       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  0 o$ r, V& N0 W& f) D
       print_r($sql);  
1 F, r7 r) X8 A8 }9 _. l       return $this->execute($sql);  # w- k  C3 Q  k! E
    }
# J$ C. G) z: {3 U4 x从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
$ t4 j8 {9 I" p/ ]- l: @7 _# V
! \% x8 x$ n6 I& l7 B" @! K攻击测试:
2 _  Z  d$ Z1 K8 e# f6 Z测试地址http://localhost
5 e# i+ G2 m! }) I0 k  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
8 ^0 d  g  N& f0 g5 U* g
/ {6 B6 @7 W5 k, j ( b; x( e  s9 A) c! V5 F" b6 i1 s
) f4 a0 L+ A4 f; ~! V4 F

$ R3 k3 _3 \* }4 G( x* ]8 H0 V  H, V5 i

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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