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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告4 |! j. u) x) F4 y. e
漏洞作者:skysheep
' |! Q# i) ^; I7 A7 Z4 u分析作者:Seay' I$ |% h% D( q; V
博客:http://www.cnseay.com/  X( p% @1 Q) q# h2 G
漏洞分析:
6 V; E2 x4 n  T6 u0 X% q2 q  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。& R" A; Q$ b. Q6 Q
/ N& |. o7 n: N& E. b- T( d) p9 d; C8 @
" [+ ^% y1 m, m& [0 s; M) d/ J5 o

1 S/ G) a2 ~2 {9 n+ W. Vpublic function account_manage_info() {  
0 B1 a! E0 u. ]6 }1 |4 B       if(isset($_POST['dosubmit'])) {  ! N7 J5 v2 l% q* g& l
           //更新用户昵称  
; C9 ^$ |; h! U: Z- \           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  : E5 t$ C  }# `! Y# H0 W2 I
           if($nickname) {  
0 m( C8 l! Q' O              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ( i* l! T9 T3 S) G8 G
              if(!isset($cookietime)) {  
3 F4 t5 R1 Y6 ^7 T7 Q                  $get_cookietime = param::get_cookie('cookietime');  
" _& G8 O( D; D4 {  Y$ Z              }  
5 m. ~) K% h$ V; z0 p, N              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  * H2 L( H* v- N6 ?+ s8 [$ O! H1 E
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
! a8 ]7 p& F. e" v* {: |              param::set_cookie('_nickname', $nickname, $cookietime);  * L7 K, L/ v6 _$ t, T0 S
           }  7 c* I, I9 c6 r
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
, S5 w8 H+ ^  Z5 E! _3 {" @5 M           require_once CACHE_MODEL_PATH.'member_update.class.php';  ) _/ M! [2 T& |
           $member_input = new member_input($this->memberinfo['modelid']);  ; ~# g0 e. k: B
           $modelinfo = $member_input->get($_POST['info']);  & W# O* l# F& S2 C8 p8 B' p8 q1 d
           $this->db->set_model($this->memberinfo['modelid']);  . m+ w7 Z, h$ ~  N! ~  n
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
9 v& x+ P. ^# C8 w9 q           if(!empty($membermodelinfo)) {  
: c7 z6 w3 |- F, \2 ~+ E7 N              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  5 c) b1 _/ w) R7 G
           } else {  ( J" b* }) [3 U* r6 M8 D4 ?$ K
              $modelinfo['userid'] = $this->memberinfo['userid'];  
, p9 k3 o- c+ I& j2 L* g* P) [& o3 }              $this->db->insert($modelinfo);  2 `1 l8 v  o  D8 p% V3 \
           } 5 N) b1 p1 j& k) E. B0 H5 O( B
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
$ p9 `6 g: l4 w+ x* B* t1 l* U在\caches\caches_model\caches_data\ member_input.class.php 文件中:" W. D9 f9 M4 B6 |. L: c' h  i

" ^) N* K4 K8 t6 |7 Q+ I
# Q5 S$ l! k- S! ]: c
8 E/ Y: n. h3 S+ H7 j( afunction get($data) {  
& a: a; a* x2 t       $this->data = $data = trim_script($data);  
% G1 c7 y. c0 P2 n' Z       $model_cache = getcache('member_model', 'commons');    n7 u; C8 a- T  L! M' Q) p6 C
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
- y1 A( ?; K  P$ c5 t4 k0 G* T       $info = array();  
- Z  r  }4 F$ S! t- S       $debar_filed = array('catid','title','style','thumb','status','islink','description');  2 X+ s- X5 B% o0 n' X
       if(is_array($data)) {  ! L7 }/ p7 V. \
           foreach($data as $field=>$value) {  # S( N, ?1 i; E6 z' v  R- o* W: \
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  - O+ i4 V% C# E/ |, d
              $name = $this->fields[$field]['name'];  ) O! I6 J" U/ i$ c
              $minlength = $this->fields[$field]['minlength'];  
3 ~; y1 ?! L6 c# d( q+ H              $maxlength = $this->fields[$field]['maxlength'];  $ S  @, t7 g; K! ?
              $pattern = $this->fields[$field]['pattern'];  7 y5 z: L* [  R7 H3 W' p
              $errortips = $this->fields[$field]['errortips'];  
+ K- E9 t- j$ G" @; O              if(empty($errortips)) $errortips = "$name 不符合要求!";  7 X  P9 H5 l  }. C$ m2 s* o& E6 z
              $length = empty($value) ? 0 : strlen($value);  
  g' U3 R' B: k" s9 K. y' R# s* p              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  5 @3 f) P3 p: t" O& r
              if($maxlength && $length > $maxlength && !$isimport) {  
, \! H- j6 H/ G                  showmessage("$name 不得超过 $maxlength 个字符!");  
& S3 o  S1 u  n# X! v% F              } else {  
( F! F1 z9 S1 J" g6 S                  str_cut($value, $maxlength);  
( Q& _% U5 u  q$ Q              }  3 C/ c" b7 }9 `
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  " u. n2 [8 R/ I; G
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
3 N# B% p; q3 G3 O$ o              $func = $this->fields[$field]['formtype'];  
- e4 Y# c" i6 l& J$ m; `9 ]' U              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
6 ~2 Q5 h1 z/ d% G( m  ~              $info[$field] = $value;  
5 H8 \! l% n* J2 H3 M           }  
0 V1 H! V) v- b7 L' Y$ ^/ m0 q       }  
9 T0 T# m2 b- }       return $info;  
. y* K8 Q6 P7 R    }
0 B5 ?; L8 I% ~8 ftrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
: x  ~% {# S' @1 v9 c( `; @, |% o) A5 l
再到phpcms\modules\member\index.php 文件account_manage_info函数
5 m8 H( e, a: N% G- `$ D: w过了get()函数之后。
8 n: Z) m% `( i5 V0 }' W  P! V8 N5 t+ D
, x' j- C5 J9 F% `' X: M
$modelinfo = $member_input->get($_POST['info']);  
5 j; V  f1 b9 K5 ^5 I& x           $this->db->set_model($this->memberinfo['modelid']);  7 I  b, r" z8 S5 N( t& u
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 _8 R+ s3 |* Z; a
           if(!empty($membermodelinfo)) {  $ [3 g6 n5 h5 S6 b/ b' ?* O
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));    h7 h" ~! \; ^8 x6 m
           } else {
% p$ z& q/ q% U' b2 J& h直接带入数据库,update函数我们跟进看看
6 A* x2 I5 R' b4 L. Y4 F# A2 u7 X3 {" n. p

6 @& D, D; c" @) Vpublic function update($data, $table, $where = '') {  ! ^  ?0 n3 S7 w, @# A, L
       if($table == '' or $where == '') {  0 N" R" y; W9 \" ^- u
           return false;  , c8 A) y( t/ B6 x; @* l
       }  
0 m  B, S# |( ]9 a- [- e% ^       $where = ' WHERE '.$where;  
( u3 X; v5 l9 p3 @       $field = '';  ; [' w2 D" N- z% T0 w4 o
       if(is_string($data) && $data != '') {  
) }% |- E0 M4 N           $field = $data;  9 t" F( H" H2 l9 E
       } elseif (is_array($data) && count($data) > 0) {  
; ~$ C! R% H/ p. x0 z           $fields = array();  ' n) S; \+ Y! ]+ g' d0 C' X
           foreach($data as $k=>$v) {  $ L$ w  R+ T! m1 s3 \2 `
              switch (substr($v, 0, 2)) {  2 d9 N% I9 _5 |$ A& P/ I* a
                  case '+=':  
0 p- o7 q  q% p2 U4 Z" g' ?3 F- H                     $v = substr($v,2);  6 v1 ?" U" P* z
                     if (is_numeric($v)) {  
/ h: |( G% N& u9 Q: _6 R2 x                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  6 x3 {+ X: f9 ]. o0 |
                     } else {  
- I) D) k2 P. U0 n$ Y. i                         continue;  " o& z+ j3 f: v( @
                     }  " S& A8 B- |9 V$ ^& p8 t, r) z
                     break;  - R  n0 H' o: x6 Y+ e4 H5 `
                  case '-=':  
  ~+ t8 p+ ]' H( i# F6 D                     $v = substr($v,2);  
7 v: q* d2 ?( Z# Y4 {6 r+ C                     if (is_numeric($v)) {  3 T* u4 x/ E  ^2 `; D; C& K
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
: A6 |# x9 e2 n' S& ~0 r5 b# u$ I$ U8 }                     } else {  
0 F* ^$ ]8 U( B                         continue;  
( }0 I6 O; m1 {' ~                     }  ) {, h7 V  p8 j
                     break;  8 x$ q2 O  K: Z7 O
                  default:  + n' [* z) C  F3 m/ C
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  0 L! @6 _6 f) t6 P6 Y+ G
              }  
/ G+ Y  k6 }# E( p  o- i$ y           }  
7 c8 E) d2 Q9 K' `# K+ L) e- V; s) V           $field = implode(',', $fields);  
; }# a. S& I3 W$ l9 H       } else {  " Y% ~6 q+ I. h& t
           return false;  4 P1 ]6 Q5 |6 q% B$ q
       }  
8 ~; d3 m$ `1 R9 e4 e; ~. Z       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ( N3 z: T# r, `+ F. X, x
       print_r($sql);  
6 w, ~" T* G$ X) `- m1 `7 s+ x$ U9 P       return $this->execute($sql);  ! m. J; X) o- i+ ]& n$ W
    }
: s( D- ?4 v% _1 b9 v8 L. k- t从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。" \0 T0 ]$ N$ \& X

  E" V* @& k5 z$ w+ t& ?. h; l* Z5 k攻击测试:0 O) N$ D* ?' [  m5 i' b( a
测试地址http://localhost: v* R' s& d% q0 q# A
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句) o7 m: ^+ S5 |
; I, ^) E9 Y8 I9 m( v6 ^* T

* C8 y4 n9 _( Q
5 k  g! A( [9 L. R9 l
# O) Y' H9 X6 Z0 l6 S! H  z0 z2 T( W# H0 i0 Y; s1 q" p1 R

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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