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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告/ U* L- W, `9 P) F% B* m
漏洞作者:skysheep
: M: W1 N1 Y/ k. O! V2 s/ D分析作者:Seay. z5 a6 H0 u% p
博客:http://www.cnseay.com/# n# J# g. e+ Q7 H6 g
漏洞分析:
: G4 H7 @& ?; m( j  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。: a/ ^% h; X8 d0 g8 I- l( D) L
' O, i7 w8 x* r% s! J: [
/ \5 l' L' f+ f- K8 Z: f5 Q4 h
4 W6 C* D# `  a4 P: j, M' V
public function account_manage_info() {  / G+ j4 P1 v6 z+ [6 }4 f
       if(isset($_POST['dosubmit'])) {  . q9 Y- A$ K; H. Q2 ?1 X
           //更新用户昵称  9 ^8 U- ]4 d  U0 v& W% A
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  - W9 I2 d: Z) C- f: G' ?
           if($nickname) {  9 I5 x* a! q" h6 n: p& M( K+ p
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
) L! g% t4 b8 c3 y2 G( H& C- W              if(!isset($cookietime)) {  + N! c/ D" n3 D% ^6 L( ]$ I
                  $get_cookietime = param::get_cookie('cookietime');  ! b5 |2 e7 S+ G$ u# {/ {) N
              }  
/ \( U1 d7 W: x4 q$ i              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
& c' P  D% ]% \1 F% @              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
  o( T$ u9 V! b/ j              param::set_cookie('_nickname', $nickname, $cookietime);  
- ^! c& q1 E" H2 J$ T! s           }  
5 A+ g9 }8 z- w4 j% W: [           require_once CACHE_MODEL_PATH.'member_input.class.php';  
0 q! {% X2 G3 L( k: |* O           require_once CACHE_MODEL_PATH.'member_update.class.php';  
' W% K" R& |! y. D           $member_input = new member_input($this->memberinfo['modelid']);  
; T' f5 j6 K& V, T           $modelinfo = $member_input->get($_POST['info']);  5 \5 \" J7 b$ O' u# ], K
           $this->db->set_model($this->memberinfo['modelid']);  
* y- b! j6 p1 A           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));    D: R; g& K$ E  V% e; [  O7 H7 B
           if(!empty($membermodelinfo)) {  
& {  Z/ F; Z1 m; @# a8 w* D, O/ E              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
: I/ }% s. U) W  j# L. N( ]! v! k9 E           } else {  # y# T- Y1 H9 N8 l0 ]5 |+ x3 H! s
              $modelinfo['userid'] = $this->memberinfo['userid'];  
- W- [0 l' J$ ^! b              $this->db->insert($modelinfo);  " R6 t; ^$ a! F+ @6 k
           } ! o. I% M  U. b- l
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,! Q5 }  h# y, l
在\caches\caches_model\caches_data\ member_input.class.php 文件中:3 g  M: S/ P9 `2 h9 }% M
, P4 g! y! x" F0 M! O4 L  e# k
  B- z, M" p" V$ C" ]
0 p- G+ I( q  L+ }* K: p
function get($data) {  
( ?6 f6 {9 S4 L2 v       $this->data = $data = trim_script($data);  7 N0 ~! y- Q. g3 ~! D9 l# X
       $model_cache = getcache('member_model', 'commons');  6 o% a! H& m0 |5 u, U, b7 f. M0 _
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
+ h- l# h) W$ r8 ~6 H       $info = array();  7 d; `' g4 H' w4 f5 f$ b- B
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ( `2 @$ U$ N( `- [& ?- F
       if(is_array($data)) {  
* A- ]- ^' n+ _0 w           foreach($data as $field=>$value) {  ; f- e7 Z* [% X; G4 s. D
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
8 \4 e! D3 |8 O& O0 b/ \              $name = $this->fields[$field]['name'];  8 g+ m3 l, p8 n( f* a) d
              $minlength = $this->fields[$field]['minlength'];    j* e' N& Z. _9 O0 K
              $maxlength = $this->fields[$field]['maxlength'];  2 j) y7 q3 c" C% C7 N, w/ s% @
              $pattern = $this->fields[$field]['pattern'];  9 b$ |0 P( V$ _. G7 Q$ `
              $errortips = $this->fields[$field]['errortips'];  
4 }8 Y- e& s7 C              if(empty($errortips)) $errortips = "$name 不符合要求!";  6 E! P9 |7 m2 B9 r; ?5 K* ~6 \
              $length = empty($value) ? 0 : strlen($value);  - V) J" C) _. p) _/ f
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
& B+ g+ o( @# i- H3 A& f              if($maxlength && $length > $maxlength && !$isimport) {  5 Q$ _9 u  M2 j* o* i) F; t3 H
                  showmessage("$name 不得超过 $maxlength 个字符!");  
( M7 m+ j1 I6 `( f( Q, ?% ~+ _              } else {  1 {/ O& {& y/ |& K
                  str_cut($value, $maxlength);  $ Y0 m6 r/ l- ^8 ?7 {! J# }) Z
              }  
  O9 {6 k# P) ?+ [1 ]! @; X, u& J4 B              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  - u$ E' O! i: G' {: ]$ u, i
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  & {5 }$ d8 e/ y/ C1 |
              $func = $this->fields[$field]['formtype'];  ) t9 y! N  f( X" I! m5 p4 f
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
( M9 x. _* o/ H; l              $info[$field] = $value;  ; P7 l* V. f+ _/ P, @
           }  1 e" w& m  ^( H7 u/ G. |
       }  
/ d( v5 @: v  d) [7 S0 x       return $info;  
( q1 G$ h4 m) y    }
8 n* [2 i4 D$ O- b6 Dtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
# X* b+ ]. o% E+ H5 J6 F
) r" n- i1 g- R! m5 y$ x. ^: o/ w再到phpcms\modules\member\index.php 文件account_manage_info函数
7 ~% c, U- W6 f1 g过了get()函数之后。) A, M6 R9 J! f' e: D
: m/ T0 t* m9 ]1 |2 b. Z

3 A/ L0 x' W4 Z- ^4 c$modelinfo = $member_input->get($_POST['info']);  - ^2 ^* Z. l# v  I) p( M
           $this->db->set_model($this->memberinfo['modelid']);  6 _) d' p& L$ Y  B
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 N' J% q4 A6 M8 _7 ~5 ~0 a5 e- I
           if(!empty($membermodelinfo)) {  
$ l7 y  P- e' F1 ^4 b) y3 Z              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ( Q3 b% Z' {# t& Z3 i! r9 P/ s* w: L
           } else { " ~/ `: q  m  y5 @
直接带入数据库,update函数我们跟进看看
; e9 i8 _" F/ A& G* `1 Y* j( `  N, n# i- h" n5 }' p2 a
$ C* J9 a" j, U4 l) g
public function update($data, $table, $where = '') {  5 ^4 b/ \. c: X, R
       if($table == '' or $where == '') {  ) \% I8 {( r1 r# P% S8 X' Q
           return false;  
4 n2 ~  g- f  f. ?9 ?2 a       }  2 q& @6 y: u* |$ F1 C5 y5 ]
       $where = ' WHERE '.$where;  
: Q2 |1 `3 z. B, s       $field = '';  
$ {. K7 q3 b- o- M% v       if(is_string($data) && $data != '') {  ) j* L4 c# @  P+ n: W& u; j
           $field = $data;  7 P8 T) P/ P8 e
       } elseif (is_array($data) && count($data) > 0) {  6 v, p  d) ~! L( v+ x
           $fields = array();  
8 B: }3 ?- \* _  X1 g* u* m2 z           foreach($data as $k=>$v) {    m+ W; Z# o4 ~: p1 g
              switch (substr($v, 0, 2)) {  
, C1 P  C1 D0 y* v" ^) u* U! ?8 y                  case '+=':  3 F/ g- b3 t3 E& I
                     $v = substr($v,2);  . m/ M6 s0 u4 @3 k$ Q2 a
                     if (is_numeric($v)) {  
8 `) i+ R4 l/ e( f9 I: p; B                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  & R3 Z! ?% l$ W" R" p& I
                     } else {  
2 {8 w- L6 f* @! R, o6 Y& l) _0 j                         continue;  
1 Q0 a) l# N7 `3 w                     }  
* c, W6 D9 ~% L8 H8 d8 O                     break;  
! D( F4 D: q( U, u* |# K                  case '-=':  
2 X/ O" p3 Y5 i8 l* i, y7 S! y                     $v = substr($v,2);  
5 h7 i3 m5 W& `# o                     if (is_numeric($v)) {  
3 e+ y% i  _2 T9 G  E! p                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ) D, j$ _2 R) }: h$ ]/ }
                     } else {  
8 c# X; w  z" p. H) x                         continue;  
# f, p5 ]$ J8 E% q( U4 m                     }  . |& y# W( M* j7 X1 g5 |
                     break;  
$ u/ Z) G" U7 P9 U9 K                  default:  % J( v& ], M$ k5 g, c
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
; x. ?* k( L8 h5 N+ B              }  
5 m- Y$ e' F! n) D           }  : i; _. v& b( X3 O; u8 k/ a- h4 U
           $field = implode(',', $fields);  7 T$ j7 F6 t# o8 g( i8 x/ X0 K
       } else {  
, [" S" D( V1 }) `8 [           return false;  4 f! s2 D4 m6 T
       }  
' D- q* c1 N# W1 z, X& y: x$ h" R       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
, r, L4 S' p0 A# I- |. C       print_r($sql);  
/ _0 z8 s* Q: K7 |       return $this->execute($sql);  
/ i0 [* ]3 K6 m    } 3 l. U+ K- ^7 M
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。- Z: T% @* r- l" ~+ c

" J( r3 p. H8 k# f5 |# G; g  G. ~攻击测试:( g7 O" ?& m; `, m0 n  h( X  _
测试地址http://localhost' P& C3 M! [* r8 h- ]
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句9 j' @6 y9 j* W$ G- u
! y5 V7 Z( M6 q  o# o, r1 ~
* O) w" R5 F0 E+ ^9 i2 u2 K

$ J# O- B- X1 l: j9 G; c5 o+ p2 V5 |
# V$ m$ E& R6 ~% J
9 Q1 H8 K# _6 }0 b* k$ w

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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