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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
4 c+ _2 K% R1 _, @& d/ s9 Z, f漏洞作者:skysheep
' W; h+ d& a4 B分析作者:Seay
0 `! L. ]( n1 ^8 c博客:http://www.cnseay.com/, K  G  a9 I* P2 ^' s0 D4 z
漏洞分析:
' B* Z# x, `8 D6 u  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
! |5 l: f' a  Y( d( ^) g8 C8 y% P! G2 G. ]/ p; J4 F& x3 w

7 T6 P& E  y2 [' L$ v* f
8 c9 W9 O2 G4 N2 F. rpublic function account_manage_info() {  1 C3 f3 k- m5 S
       if(isset($_POST['dosubmit'])) {  8 j& T$ z' y* G2 t0 M
           //更新用户昵称  - E1 A+ F5 K* T3 E$ C: `5 N
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
6 j' ]! f7 M4 C0 [5 R           if($nickname) {  
' K# f$ c. p! K! S. `              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ' G0 \4 y' f5 r- S- G! G
              if(!isset($cookietime)) {  
) d! o4 v, h0 x/ M9 s5 s                  $get_cookietime = param::get_cookie('cookietime');  
9 o/ C! P) r! l1 f7 t) F              }  
6 G, `- I6 S+ _. Q3 l6 a              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  1 |* p3 r% ~8 ?) ?3 W
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
3 k) }, T! H: [0 X8 l              param::set_cookie('_nickname', $nickname, $cookietime);  7 h; ?" @: ~, a9 {7 g, ^
           }  
( x- j; K' A" |: B9 T           require_once CACHE_MODEL_PATH.'member_input.class.php';  
9 V, f: G! R& w9 u           require_once CACHE_MODEL_PATH.'member_update.class.php';  
$ F1 B& D! f' l3 \- ^           $member_input = new member_input($this->memberinfo['modelid']);  . e$ O% \+ x# {
           $modelinfo = $member_input->get($_POST['info']);  # |+ Z; {' ?3 o* o
           $this->db->set_model($this->memberinfo['modelid']);  , w8 P) B7 V$ o
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
: u( x/ {. x0 d- l; Y2 Z           if(!empty($membermodelinfo)) {  $ H: c/ Z) p# \; O+ j
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  % n6 l( `0 q! l. a7 Y9 _
           } else {  : P8 Z( a5 x4 g: y: \" A5 _0 Z
              $modelinfo['userid'] = $this->memberinfo['userid'];  . `1 ?5 P1 Q) U* b. `' k
              $this->db->insert($modelinfo);  : a. @. `' U; y8 C  |
           } 8 H7 U& O  V# V( }
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
8 n4 c2 v  j! H4 {4 h& V在\caches\caches_model\caches_data\ member_input.class.php 文件中:
7 m  B" h  H/ @1 t2 N+ w1 j) Z
- X# p9 l$ m0 b3 o$ L

. y# P" ?) n/ _" y  a) kfunction get($data) {  7 \. P) w/ j" |" w. M$ U
       $this->data = $data = trim_script($data);  
3 h, O. X5 K( A, O2 r       $model_cache = getcache('member_model', 'commons');  $ k$ z- ~) x5 y: |( I
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
3 J- N4 D+ }, d4 v1 x( u       $info = array();  
, c! V8 `, e  t       $debar_filed = array('catid','title','style','thumb','status','islink','description');  , T7 ?7 I9 ^9 m9 E: o! T4 {& E
       if(is_array($data)) {  
0 x5 H1 W6 x0 B2 ~8 y           foreach($data as $field=>$value) {  
) P( @+ N* a+ W4 S) L- w8 e" c& m              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
9 n9 d$ d. R4 `% S" x" O( j' O              $name = $this->fields[$field]['name'];  ( i* _# \$ l" Y# Z9 U( X
              $minlength = $this->fields[$field]['minlength'];  
: F# Z7 c+ m2 s+ x, j              $maxlength = $this->fields[$field]['maxlength'];  - I9 c  Q4 T( {5 F% ?* V- [
              $pattern = $this->fields[$field]['pattern'];  9 E8 ]+ L) b! S
              $errortips = $this->fields[$field]['errortips'];  
6 q- i- A  J* q% H1 s              if(empty($errortips)) $errortips = "$name 不符合要求!";  
9 k, D7 B% B2 D' F. H( w              $length = empty($value) ? 0 : strlen($value);  : Z7 k* J5 V5 |% j: t, K7 w4 G* R: i
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  0 k- K9 @  P& o" C& G$ a
              if($maxlength && $length > $maxlength && !$isimport) {  
* I+ g( c2 O5 l2 U# T                  showmessage("$name 不得超过 $maxlength 个字符!");  
5 f3 j3 s- j4 M/ W              } else {  ! R2 F: c; d- }0 I, O
                  str_cut($value, $maxlength);  
! m. W( m- A6 q0 d  \              }  
9 e) }6 c+ V. w) D3 d) l              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
- V5 S1 A: ~3 V! I/ g4 f) R4 B6 w                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
! s9 j7 x5 Q1 G3 K( D6 p              $func = $this->fields[$field]['formtype'];  
6 @4 F0 C( k& k              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
' f" z& u/ p3 O- H' g              $info[$field] = $value;  & o1 \) f- d/ D+ ?! m9 X
           }  
4 C/ L; k, [' Q5 f2 ~! @$ J5 `0 C2 v% C) t       }  : C& U5 H0 F- ^9 z" j: ^
       return $info;  
& O; ]* o( }* \5 j$ u7 K; S    }
" ^6 g6 E$ a9 i/ {trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
- h0 X' e; G" g4 |6 Y! ]- L0 z. I
" h: ^6 d, W5 ~" {8 X1 Q9 p: e再到phpcms\modules\member\index.php 文件account_manage_info函数
! G! X4 W$ G$ [  ^( n9 M& U6 g过了get()函数之后。
9 d1 G6 V+ \1 o& ?( x
8 q( p& _! J7 S$ q# V
2 C4 G! s0 C% y8 g5 I; H$modelinfo = $member_input->get($_POST['info']);  
" q3 u* d, P9 [( V  J' h; x& i           $this->db->set_model($this->memberinfo['modelid']);  
6 U* Q6 U- o' y# S3 z& H           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ; ]' D; x2 V" t
           if(!empty($membermodelinfo)) {  
2 _  f! b- C$ O2 n              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; B( @$ z  t- }6 e! q
           } else {
) e" E% ?- \0 s( b' g直接带入数据库,update函数我们跟进看看4 ^8 M5 p- \3 h9 \

% \* K/ O8 K, F* Y6 \
5 ?5 p* F7 S( Lpublic function update($data, $table, $where = '') {  
% C4 G: @5 t' z- M9 e+ F       if($table == '' or $where == '') {  , ~9 B( H0 x+ d7 Z& p' J( i
           return false;  
6 [6 `5 H' w7 l3 A       }  
$ u  l9 s: l- @% F( W8 }! @# j       $where = ' WHERE '.$where;  & V/ @- U5 _1 U  E' i# o8 K
       $field = '';  ) F$ o- ^2 Q0 `5 F- ^) z
       if(is_string($data) && $data != '') {  
$ R" V# v# r9 w5 l3 {2 G           $field = $data;  $ }5 }/ N" H" W6 r2 ^4 @
       } elseif (is_array($data) && count($data) > 0) {  ' s- z7 i5 D6 ]$ Y& x* H, `
           $fields = array();  
8 X7 O; A$ ~% @5 k: ~6 D. X           foreach($data as $k=>$v) {  : q. ?, B; {- n/ T8 B& B
              switch (substr($v, 0, 2)) {  * U9 ~1 ^3 |( Q
                  case '+=':  3 t. L8 \- k" [% b) K, ~' r4 B
                     $v = substr($v,2);  * A5 @6 @6 Z% P8 X' ?5 X4 k
                     if (is_numeric($v)) {  
( Y/ w+ g- j. r$ B0 D                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
+ \+ M: T, `. D" b0 |- u                     } else {  $ p9 u& u& o/ w, e% ?: m! r
                         continue;  
$ y' Z, F9 U$ e/ V6 k7 m- c                     }  
, ?+ w2 `# S* t4 R) }% a, F                     break;  , q+ H0 f' p0 P; c5 W" M4 ^) d; d
                  case '-=':  
' Z+ m) \6 j# G$ s0 O* I- N                     $v = substr($v,2);  $ h: m/ |4 E5 J; ~  j
                     if (is_numeric($v)) {  
8 M3 ~% x2 \  ~+ Q, Q) N                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  & Y4 L0 q/ p- e0 Q! d0 |
                     } else {  : l) t& c  O% v1 s2 S+ v
                         continue;  # l) J! E0 W  O% S- g
                     }  
+ N- F1 C$ m8 L! y$ [9 y) L3 ?' d                     break;  # n1 a# f  G5 B; x$ L
                  default:  
8 n' x# a/ t- h+ b7 D' I                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  3 s, R1 b+ x0 p
              }  1 ~2 z: o+ r) `0 i0 D) C* u
           }  * Z# ?4 h! T  `# o( c. }
           $field = implode(',', $fields);  : d) M4 }0 a; ~6 i
       } else {  2 d' O0 u5 K, h* F
           return false;  - I$ I7 d6 I6 |* j& J
       }  
4 q" }# f% \+ y: u. K       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
! u' J0 ?  n( t. u: r       print_r($sql);  
) V: C9 X; ~/ @& S       return $this->execute($sql);  8 r% X- C/ d; ?* y5 |5 N& ^' V3 ?
    } 7 ~6 V/ ^. w( {/ o: i: m
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
( L5 k' P, j; c5 V+ q+ P; G7 {* H' A  _. w, `+ ?
攻击测试:' [3 G' a7 J6 G0 B0 J
测试地址http://localhost
$ u$ z+ ]. W& A; c* B0 @2 r: L  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句  M; `( |& l5 x

# D  M7 U, n2 s, P5 U 3 ~" Q/ S1 T: s! q1 o
7 d9 }+ l5 }* U/ U: r1 p9 u

6 }% x2 V9 A3 }6 c: J) L' `- Y  s6 o
5 [' g" n, l! s% @" ^7 }

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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