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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告! b. B1 r2 N7 f6 I9 t$ [
漏洞作者:skysheep; p5 y* T1 c: m: ~; f. r
分析作者:Seay8 a  }4 `; N; g2 \+ S- X
博客:http://www.cnseay.com/
! e" X- P% }; _# x漏洞分析:0 B6 w) N/ j! \. W* {! ?( V
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
; J& E% H+ N7 f) D  w
. K$ y! J0 R! s' \
/ ]! r% G6 s$ h( _5 ` ! d5 P( G' l4 V6 t, {! t) i
public function account_manage_info() {  3 M3 ]( @' J- f3 m0 I" N
       if(isset($_POST['dosubmit'])) {    K3 D% }' V6 E8 Q6 T" N. i
           //更新用户昵称  , ?( _6 r9 `' f
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
9 m1 V' K) T' P+ p9 t           if($nickname) {  & l; T. [4 f$ h' }. i5 m- x0 D
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
1 i" W! {& K% B              if(!isset($cookietime)) {  
6 o2 n; E4 w' H4 Z, \/ j) [) ~% k7 G                  $get_cookietime = param::get_cookie('cookietime');  - S. L* H8 i2 v5 r
              }  + \' z3 `7 s% T# [
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  - @% J* Y- k6 `. O4 `4 D
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  2 L& w5 R( l1 b/ v$ }' U, P
              param::set_cookie('_nickname', $nickname, $cookietime);  
7 f$ y: L  |& f7 j; F) [$ @/ {           }  * V0 V" z, Z% z+ ?6 R. e
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
: v( r' ~; @! p           require_once CACHE_MODEL_PATH.'member_update.class.php';  
1 b% J) ~4 @8 T, ~1 J           $member_input = new member_input($this->memberinfo['modelid']);  ! x) m) x' v5 e3 F% H1 D$ R' y7 u
           $modelinfo = $member_input->get($_POST['info']);  $ s# v( J% Z- ~/ P; j) O* R+ Y# d
           $this->db->set_model($this->memberinfo['modelid']);  
4 ^: {0 ^! ~  \' j) B8 ?7 n           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
3 `9 m  r$ Q8 h$ ?; W  M* Z           if(!empty($membermodelinfo)) {  ! r8 ^" ]  a# _2 W
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
# i, E  T& r; x1 A. c& I           } else {  , s* g" y( e" S3 e
              $modelinfo['userid'] = $this->memberinfo['userid'];  , l; D% T9 K* Z" }3 C' z  N" V
              $this->db->insert($modelinfo);  1 V+ n/ c$ y/ G( N$ z$ K" r- t
           }
7 k! u% Z! q6 i  i. ]代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
$ j" m5 R' u- W% Z6 o5 j, K3 j$ g+ L在\caches\caches_model\caches_data\ member_input.class.php 文件中:
* u, l; C) G/ Q, m
- G4 E: O) _0 @! V+ B# k& C# K( g' L2 N8 D* c3 i% p

8 z& F- i. C. q. Q! Z( P- mfunction get($data) {    u5 n( d7 l- e# ?! Z: [
       $this->data = $data = trim_script($data);  # [/ p& s7 c7 s; S) E/ `
       $model_cache = getcache('member_model', 'commons');  
. T  u  E3 S) |7 n* D% u8 |       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  ( G$ ~: c1 j! J& a% J2 C5 s; l# x
       $info = array();  7 ^( Y& K6 T+ p3 y( v
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ; l0 u  l" S1 j3 ^
       if(is_array($data)) {  
. {2 \. Y5 l$ e  G           foreach($data as $field=>$value) {  " \0 R" k# m- V2 U' h; ~
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;    U" h5 {  j6 q# u+ I5 Q; L) M% p3 `
              $name = $this->fields[$field]['name'];  
8 p, Z! b+ {' ]" X9 h              $minlength = $this->fields[$field]['minlength'];  
# p/ Y7 ^* [/ `- P# g9 Z              $maxlength = $this->fields[$field]['maxlength'];  
4 }: |/ I3 ]  e& u6 N5 b, \' Q              $pattern = $this->fields[$field]['pattern'];  
6 h  t6 M. k, M3 n              $errortips = $this->fields[$field]['errortips'];  ; u% U  K4 h. I9 _  d* o" S
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
" A0 B) J3 A& F, G! s              $length = empty($value) ? 0 : strlen($value);  : r) F  D+ {5 z# X) b
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
5 O/ P; M, F; C6 E9 j6 A              if($maxlength && $length > $maxlength && !$isimport) {  
" B. o% r( |4 Q1 A+ F                  showmessage("$name 不得超过 $maxlength 个字符!");  
9 Q) o- p* f. \# V1 L              } else {  " I/ N6 Y- w6 D9 @% [& Z; L
                  str_cut($value, $maxlength);  
) G- F; m- z9 n" J. G              }  + K! C$ C9 p1 N2 S- _
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
2 E, H  f( [' Y& Y4 m                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  7 ?& s, R: ~5 a" B. c
              $func = $this->fields[$field]['formtype'];  : O2 e+ k2 G1 |: ?6 f: G& b% k
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
3 O& P1 H) y) U4 S8 J              $info[$field] = $value;  0 j& l4 G- n# u
           }  + a$ ?3 I* p" w; {2 k! ~5 u& K, {
       }  4 W' I5 b9 z$ r5 o" J7 f  c+ E
       return $info;  + D0 C3 j' }1 x' f  f5 `& d
    }
6 Q/ N7 h* P: e1 f2 R, ztrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
* ^/ `. P. Q) m$ P( {% t6 N! D
9 v; g+ \% q0 N5 X( x1 t再到phpcms\modules\member\index.php 文件account_manage_info函数  j6 \5 I5 V1 ^
过了get()函数之后。
! T. k+ l$ b' f8 Z6 y. [  q0 H! W
0 p3 Z& G$ I- x3 ^$ m8 `" ]# W
+ B/ J, T8 o- N' M- O$modelinfo = $member_input->get($_POST['info']);  6 `9 Y% T( Z4 t8 l6 o
           $this->db->set_model($this->memberinfo['modelid']);  
2 Q7 ]6 m. f9 K1 c           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  , p+ n2 [+ D0 j
           if(!empty($membermodelinfo)) {  ; v' P0 \& \3 G; C/ e# K1 g
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
( L5 I4 v% j+ p9 D           } else {
* P/ ^: Q* ?. I% n; x! O8 m直接带入数据库,update函数我们跟进看看% X2 d3 Z6 W% `3 e5 M: }9 _: l
2 s7 V# i4 V& H# Q' e; g
7 F9 `) I5 U6 e% H0 q5 ]
public function update($data, $table, $where = '') {  
8 H/ p9 d* x' Z       if($table == '' or $where == '') {  
1 F% b* X; v- _/ P7 c: i) T* O           return false;  
5 Z( N7 z' I9 `3 x/ v       }  
" y6 u0 Y% H" _" J+ }! [       $where = ' WHERE '.$where;  ' m0 R" D, l/ P( [- Z2 u
       $field = '';  * E" A# b  u; Q3 N
       if(is_string($data) && $data != '') {  
) n. p, N' e* ^; h2 P/ H           $field = $data;  
  s+ h+ O6 T2 r* U$ z) g( h       } elseif (is_array($data) && count($data) > 0) {  & x. B/ l+ A, \0 V' r7 J- A
           $fields = array();  
' z. [$ \" Z& M  \           foreach($data as $k=>$v) {  
- M+ [9 J4 N$ _6 P+ ?* m              switch (substr($v, 0, 2)) {  
( R( b& }! l' X( Y                  case '+=':  
; q4 n# `6 E3 }                     $v = substr($v,2);  ( v; u% T+ _  k" Z
                     if (is_numeric($v)) {  , A0 ]( l" u: I% _
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  % }, d$ H' ?  A  O. n+ ^
                     } else {  9 P+ y9 u& ~' [: Z: i
                         continue;  $ x8 p, E2 q$ f
                     }  
+ r7 r  E1 S+ i  [% p5 P  }                     break;  
- O4 K0 m8 B# y' x; L                  case '-=':  
5 V- f3 K2 }: M                     $v = substr($v,2);  
: G; P: \& L' m4 Y/ `! }: W* A                     if (is_numeric($v)) {  1 Y8 h2 e8 r- A6 C6 N5 k
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  . D# Y0 T, {) n% A8 L* c
                     } else {  4 E. D3 u' y& V' }' a' k8 J
                         continue;  
& M& g8 a/ u4 k9 F3 v6 O                     }  8 K& M: [. k) `: l0 t
                     break;  
- \+ f8 k  O: V2 W, N                  default:  
# E4 X1 @0 }3 t1 Z- p0 Y                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
) I5 m, P, t! [6 A8 _, V              }  4 s$ A. R. t' E" d2 p3 D: j6 b
           }  
4 {' g1 o4 x" W" O1 ?           $field = implode(',', $fields);  % Z2 n, f* @# s& n
       } else {  
. z- v1 P5 x3 `3 d* W5 o           return false;  
3 @7 F# t; I7 s3 n. t+ o       }  
( V0 q! R  i& T1 b       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  9 h/ ?9 _$ s5 j3 R) N0 F- n
       print_r($sql);  : t7 k+ `) b- {
       return $this->execute($sql);  2 |0 E3 q6 \2 M8 X  B3 p
    } ) y. V/ Y8 I5 p% U) Z6 A
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
: T" L7 g, }, ?' s. m8 q% Y6 _5 j5 M4 Q" g7 N+ B1 D/ c  S' A; e5 X$ e
攻击测试:
! }9 P; [' e% x; e( S/ y# N% ]测试地址http://localhost
( e  q. }8 `3 D  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
  k! U# [3 ^( [: l# Z- X( |- B
5 J) O0 _# j8 C2 w" l4 i$ H
* \9 \8 ~* X8 u- V4 N
/ }1 C1 V8 Y4 _) @+ A, m: z
9 g7 a: F# j- r+ y! {. |3 Q5 t/ o5 i

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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