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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告* |7 G. ?3 k# |# A; s- W, F
漏洞作者:skysheep4 a3 m) X! C1 c$ R! n0 v" r
分析作者:Seay
6 l" c9 X2 {2 o4 }0 j5 s, L! L6 g博客:http://www.cnseay.com/# R, S- k" z2 [+ z7 y) X
漏洞分析:
+ }$ [' h) H! ~/ l  C  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
4 N, W6 v2 t4 ~3 v& A# A; V9 M" }
* p- e' R; i2 t* @' e& T
* r6 m+ C7 G3 r- {' H: q3 p 9 m; |( G/ l5 T
public function account_manage_info() {  9 a1 ]# c; J) q+ C0 a* {' Z
       if(isset($_POST['dosubmit'])) {  
4 ?1 T" |6 [) ]           //更新用户昵称  
1 I8 ?2 p1 ^5 {: C* z4 _           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
7 a) U) B# v' @8 v           if($nickname) {  
& i0 m0 j6 P( E! l              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
% G/ A/ E# Y2 n: D( }9 q" x5 \' k              if(!isset($cookietime)) {  3 E. J- O. [8 ]$ l% L
                  $get_cookietime = param::get_cookie('cookietime');  
9 p  O8 I$ y( Y5 B2 P! l, x              }  
3 q* z; J3 @: U- ^              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
& o' u2 I6 ~, |4 a, {8 \5 M* {              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  5 ^2 y6 m; P2 R. W
              param::set_cookie('_nickname', $nickname, $cookietime);  
, u2 x8 }9 m7 ]5 R" Y$ v  U6 m           }  " s. Y0 ^! U; V
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
$ E) |+ `) o6 G' ~7 j           require_once CACHE_MODEL_PATH.'member_update.class.php';  8 U( `; G2 T- O
           $member_input = new member_input($this->memberinfo['modelid']);  / ^, K6 N1 \, l7 X6 ~3 _
           $modelinfo = $member_input->get($_POST['info']);  
+ y. [( s2 `2 m4 Z. Z0 y( \8 R8 ^+ h3 ^           $this->db->set_model($this->memberinfo['modelid']);  2 E- k( }+ v4 ~/ K5 q  d* ?4 [
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
4 z! @9 r3 q% \4 h           if(!empty($membermodelinfo)) {  3 d2 t: X8 j( \* }& o0 t
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  8 \$ z- u2 T. j( B8 M, {. K
           } else {  # f1 b( ?% d8 s% @" o
              $modelinfo['userid'] = $this->memberinfo['userid'];  % T* p( c$ j$ a1 q* G6 [
              $this->db->insert($modelinfo);  
) |! M8 N# n% V4 I  v           }
* y1 J% y& a" W6 C5 E) W代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
6 q5 i; |& |+ Y在\caches\caches_model\caches_data\ member_input.class.php 文件中:& }, t! J4 f' K
5 ?' u$ E% G4 ^' |- z+ ~1 n- w' c& z

( g- D5 \0 y7 d+ L. K
6 O1 f5 f, ^& C; ~4 e7 W& ]6 C! hfunction get($data) {  2 g# y! }, ?, j
       $this->data = $data = trim_script($data);  / Z, t/ t5 Q/ L3 r% _
       $model_cache = getcache('member_model', 'commons');  
' N% E3 h4 }* v; S7 L# Z" a       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  ) G! v6 K& C1 N" _6 R! t
       $info = array();  0 ~$ z4 W! D/ n6 }
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
" e; l. Y2 \9 n8 u0 D6 ^/ s5 _' V6 @       if(is_array($data)) {  
) i( E% g  R, m8 U7 @1 i9 K           foreach($data as $field=>$value) {  # u! y( H$ O7 L% _4 w& `, \+ Q0 h
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ( x5 g) v& b; T5 [, Y% V
              $name = $this->fields[$field]['name'];  . O- K4 z1 @$ h5 g* S  n
              $minlength = $this->fields[$field]['minlength'];  
  F1 M* E6 g8 s( ?- e8 l              $maxlength = $this->fields[$field]['maxlength'];    h7 V4 v# ^6 K8 ~  B
              $pattern = $this->fields[$field]['pattern'];  
1 V! s% P4 Q. S; u& d2 b& n* f7 }              $errortips = $this->fields[$field]['errortips'];  
- t: ?& O( S' I% t* ?  e              if(empty($errortips)) $errortips = "$name 不符合要求!";  + k  N# A5 j' y  V% s6 b% p0 g
              $length = empty($value) ? 0 : strlen($value);  
6 ]2 ]$ T9 P. b- H5 P7 e+ I' ~              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ) p9 B/ b" I. B* d" e; N
              if($maxlength && $length > $maxlength && !$isimport) {  . M) n% c: T1 a" C- m. [; a& @' R4 U
                  showmessage("$name 不得超过 $maxlength 个字符!");  ( T$ w  ?1 w7 p2 {1 l6 @
              } else {  
( n- ?2 u4 @; d7 a, w8 j8 w' @  k                  str_cut($value, $maxlength);  
4 P/ P; `3 y& B) v              }  
# w' o+ X% i2 Q9 r% {) M              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  9 O1 Y1 Y' u" {, B- b/ }1 E7 I
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
7 Q  g! L9 a. Y: d' h* p              $func = $this->fields[$field]['formtype'];  : L) N2 S, d4 Z/ j6 ^) C/ L
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  " Y& r2 R8 K. h! Y3 Y6 j" m" ~
              $info[$field] = $value;  0 ?" R0 ~5 [0 C9 B* q6 U! r- A
           }  2 r" k; D& T* t9 F" _- Q: _
       }  
& P3 V3 V0 S4 P$ y) H       return $info;  
6 m0 i; g  h- q) q    } & |  z5 Z9 x  l5 \
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
6 {1 ~& P" A: ?
1 d" k7 `: Y, D) D, G. A$ r9 o3 P再到phpcms\modules\member\index.php 文件account_manage_info函数
2 R: S% H* I, g! e% X( A6 ^1 s过了get()函数之后。
1 y& w5 E! ~& s, H% _9 Q
$ H$ `$ v. _# _$ R; @" { 7 [8 P: _5 ]. m0 G+ N" x
$modelinfo = $member_input->get($_POST['info']);  
, h/ R9 ^) t9 l7 u4 X  R6 Q1 u           $this->db->set_model($this->memberinfo['modelid']);  
% R9 `0 n4 w. g, n# M6 A" S           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ' O% ?: m- a+ [' l
           if(!empty($membermodelinfo)) {  0 Y3 L7 H: w9 k# G6 P5 s7 X: X  o
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  " C$ Q# V% k& U7 P$ ?9 \
           } else {
1 _0 o+ H0 _: r, \直接带入数据库,update函数我们跟进看看# R  j" w! Y6 w' m# n& a1 z' X2 S0 @

7 A- v3 w9 Z/ T7 ~7 ~9 X # K& u; p5 q5 ~; Z' T
public function update($data, $table, $where = '') {  
% l; D3 U9 B; e' S       if($table == '' or $where == '') {  
$ _2 k! T# d9 G+ R. E$ P           return false;  
  ^, j8 w6 h5 X$ c; P       }  8 O7 i  j3 v% o: Y; o8 g
       $where = ' WHERE '.$where;  % b; `6 E  g; [/ x/ k: g; z* d7 [4 G
       $field = '';  : h6 H; W9 `4 f% x6 {/ V
       if(is_string($data) && $data != '') {  
3 r) a) F' w  k. ~. J           $field = $data;  
9 B7 R/ O* z- I" _6 J' y% c4 J       } elseif (is_array($data) && count($data) > 0) {  . |! _# f1 v1 Q$ H* }
           $fields = array();  % j. b. t6 W6 M9 C
           foreach($data as $k=>$v) {  ! I! t2 ?% c% M1 E! }
              switch (substr($v, 0, 2)) {  
3 }- \9 E7 Z2 ?; P$ ?6 G                  case '+=':  ; `; }: z# M/ r- I. ?
                     $v = substr($v,2);  
, V5 F* J+ @5 k                     if (is_numeric($v)) {  
/ D+ W4 |4 b: b& |8 w- d9 k                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  : g, C( {! f5 _8 b
                     } else {  , Q+ X9 z. T! T6 X& ^1 o
                         continue;  
% c" X3 T: ?8 t/ D! c, Z  m3 |. S8 H                     }  
; H& g) k9 A# H9 I                     break;  ) ^# `$ y2 H8 x" w9 S& `# M
                  case '-=':  
$ B$ p9 I5 d1 k% S; e  T, \& t8 B                     $v = substr($v,2);  
( n1 N. {0 ^4 A/ K                     if (is_numeric($v)) {  
) @+ f! B1 t, n( Z& C                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
& @$ h( u* x) ]$ }/ _8 T                     } else {    E4 K$ c* a7 y. P6 {* L
                         continue;  
" d* f6 C2 a7 {6 B& X! L  d                     }  
  n0 R/ ^, P1 k) d* a                     break;  
5 T' M- N, Q& c; i' Z1 X                  default:  & ~- \- [5 G' t- N( G! n. ]+ s
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
1 O! G* {+ e  y" o7 l/ g/ ~              }  9 o* b) V/ q3 {! J, p9 V$ m; Y
           }  
. Q1 z0 B: u1 a. Y$ [0 G  r" J           $field = implode(',', $fields);  
& X' |) q8 i( C8 ?, a# k       } else {  
. Z* ?: A  i  K$ h% j           return false;  
1 z% b! j" G3 R/ l' Z8 }/ v0 C; \       }  
. @. c) Q2 s& a       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ; `: \. f6 ]: s/ |8 t
       print_r($sql);  
% Y0 d$ I1 Z; x8 k$ G  R       return $this->execute($sql);  
, ]/ a- S2 w8 ?$ P% l    }
, D5 s0 M5 @. Y0 N( V; \. b从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。/ k  @9 Q* ?8 ~5 Z9 C) T
1 E( h% P3 W/ H& n
攻击测试:
, j) Y6 d( O  x3 Z$ d: h% q测试地址http://localhost- \4 g7 ?* O" p" w6 u
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
; C& V: P+ r7 b- ]
  j1 L5 l7 K8 u. F' l9 b % @* v7 e) ^+ x. f
( y, X' s3 h) p# C3 Q. i

: s8 M# X  m' G- o
4 ?8 o) }6 O7 B# ^' t" @

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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