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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
+ L7 L% C+ j  z0 X0 [6 X漏洞作者:skysheep  }+ J$ ?! ~8 X+ i; n* Q9 }3 X
分析作者:Seay
8 D. E; T+ L  I2 n+ c% T& K) ]博客:http://www.cnseay.com/( u5 P6 T0 _" }7 j. B" g- b9 G" n) k
漏洞分析:2 D' D" P  }4 m& r. g' d' W
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
2 B  `2 }) g2 |+ a6 B' D# g: g+ [9 f. Y2 l
  m( }1 [/ K" J. }- `/ `* ~
6 e4 q, ?8 |7 Y. ~1 t
public function account_manage_info() {  7 M! P9 N$ p! s" K) Q
       if(isset($_POST['dosubmit'])) {  : K6 _# h' z  @1 P+ q. {
           //更新用户昵称  
: J8 W9 P) q1 v8 S% T1 E/ q( ?  W           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
) e8 H* T& L3 O2 |: s8 T* e           if($nickname) {  
- [4 G$ v0 W' \' G! ]! W              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  * s  k% B0 \8 ?& |
              if(!isset($cookietime)) {  
0 b8 Y3 H: R, m- _; r+ f& |                  $get_cookietime = param::get_cookie('cookietime');  
) S6 k5 o* G3 `- Y& _& j, `" C              }    _$ `8 D# F2 s$ B8 Y& g/ p
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  9 ^: ^2 Y  U  ?# C% g
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  1 Y* e. s+ M( }0 g6 j& L% B
              param::set_cookie('_nickname', $nickname, $cookietime);  
6 Y6 ^; x$ s) x% I           }  
- r1 v7 J8 `7 }% T+ N8 p           require_once CACHE_MODEL_PATH.'member_input.class.php';  
# N0 b+ b0 K+ y: |           require_once CACHE_MODEL_PATH.'member_update.class.php';  1 T6 L' u  h& }  ?0 P8 A
           $member_input = new member_input($this->memberinfo['modelid']);  
. I6 B/ G% U7 Q& Q! O7 g           $modelinfo = $member_input->get($_POST['info']);  ' G5 x. p& P8 a6 ~3 C
           $this->db->set_model($this->memberinfo['modelid']);  
( e/ I( ?' c1 [3 b. h: Z9 w% o           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
1 x$ |" k* r2 P) K0 E4 E           if(!empty($membermodelinfo)) {  3 U* P) Z, H. O# x8 u9 [- X$ f* Y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  : v4 n1 q$ J% ^
           } else {  
2 `2 ~4 |4 G' u( R. e" |3 |              $modelinfo['userid'] = $this->memberinfo['userid'];  
0 Z$ f' ~8 V2 ~" c  @' v              $this->db->insert($modelinfo);  
% w% `. R+ X3 s) b8 W1 k, b; J           }
; Z& x0 d1 \9 w. m5 I; c5 U代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
5 Q( D! \- K. {& W在\caches\caches_model\caches_data\ member_input.class.php 文件中:5 E; Q, g% f( t3 U: h  E, x

6 J: ]2 \& A. ?, d' G1 Q* Y5 x& r: E8 s# D4 Z

" z% D+ I! W' y1 B1 P- |0 O% xfunction get($data) {  
% h+ g- @' ?9 w. S       $this->data = $data = trim_script($data);  
7 p4 n' c1 ]& n: `, J; r4 [       $model_cache = getcache('member_model', 'commons');  + E0 \0 z5 z0 v
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
$ i' b8 C" M9 z7 D/ \9 B       $info = array();  * h5 R" l' j4 b# q' M) ~
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ! _* t* v. |3 \/ k3 K$ E! C
       if(is_array($data)) {  / k6 ^, `6 c( B. f: v+ ], D5 e
           foreach($data as $field=>$value) {  * T2 l( q+ L4 K" w. V- x
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
9 N+ ~3 e" B; c6 L+ J              $name = $this->fields[$field]['name'];  3 p& U  P" K& P9 M
              $minlength = $this->fields[$field]['minlength'];  
' X1 ]: v3 ~0 Q$ B" C$ B              $maxlength = $this->fields[$field]['maxlength'];  
0 Q$ _" r8 m% g6 X1 P* o+ ~( y              $pattern = $this->fields[$field]['pattern'];  
. _* m7 F0 c1 G) |5 g' ]: d              $errortips = $this->fields[$field]['errortips'];  
( _  R; F- A+ x              if(empty($errortips)) $errortips = "$name 不符合要求!";  
  K$ S1 ^2 B, U              $length = empty($value) ? 0 : strlen($value);  0 o4 u' K+ ~% J: A5 h& @& O
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
; B4 ^& K  U/ G8 z6 G) y              if($maxlength && $length > $maxlength && !$isimport) {  
& O$ i/ J& h, M2 D- S/ X+ H                  showmessage("$name 不得超过 $maxlength 个字符!");  ' P9 r8 ]3 ~% q3 A& N6 r
              } else {  ; I/ n" j2 U: T
                  str_cut($value, $maxlength);  
% r( |% b4 K& n# ^# B1 L              }  
- }# s* I6 p. U" t# o( }              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  0 }, S8 o' c" w* W9 C3 F
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
$ k% ]2 r4 s) G% S) m4 X2 ?3 h1 x7 o              $func = $this->fields[$field]['formtype'];  ) E. k! S% v- e8 \3 _
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  " Y* e3 p5 v( S0 u: v/ Z3 {
              $info[$field] = $value;  * g9 f# n' F8 r7 M7 J
           }  # T+ ^6 }& n/ e; p6 E5 e: E7 \4 s
       }  , r! a0 P2 o$ _6 }$ @" z
       return $info;  3 Z9 [, n# m. P$ y
    }
+ e6 j; H; j/ j; m4 E& ttrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,$ b0 \! w. [# k
: e+ n5 I' v' {  d3 U3 B
再到phpcms\modules\member\index.php 文件account_manage_info函数
( }' e# o; Q' a" y) J" W6 F4 E过了get()函数之后。
$ e! ]7 y) T" Y  a4 @( I" S8 C' K; [  @4 n. b5 _9 L: }

) s  y1 z% }5 G9 F: x" s$modelinfo = $member_input->get($_POST['info']);  2 ~4 u  ]1 @- o6 J% K" V3 G
           $this->db->set_model($this->memberinfo['modelid']);  
  {8 S+ L" ]0 u. g+ N& w           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
5 b) o+ X" u1 X- P# ~) [           if(!empty($membermodelinfo)) {  
6 ]  b5 ]# F6 t: _) Y4 m5 s7 @              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  % u- t3 X0 w' s9 Z4 X
           } else {
: u$ Z2 ?4 x" N# F2 z& w1 C" e8 }8 f直接带入数据库,update函数我们跟进看看
; h7 U' x* x# z3 a3 J3 d
, u' ~- `, Y3 t 3 M% }- Y& ~% _- z
public function update($data, $table, $where = '') {  ) u$ f2 l# E9 K1 c1 c+ _3 k, y
       if($table == '' or $where == '') {    H' h5 S/ T. @$ p( X6 D; W
           return false;  
5 k* I; f. U* b' {+ i2 r       }  1 @# Z* ^( T) J3 M' z4 h- p2 u8 Z
       $where = ' WHERE '.$where;  + l0 b) g& V/ O' Y. s
       $field = '';  
) F4 G1 H" b" U3 s7 U5 u" b       if(is_string($data) && $data != '') {  % R. G; K" A& X) ]' x
           $field = $data;  
6 U; U8 {% I6 ]9 a1 f2 I       } elseif (is_array($data) && count($data) > 0) {  
5 ?8 L5 \6 s9 y, Q           $fields = array();  $ n' J+ |, |% R/ g' T$ Y
           foreach($data as $k=>$v) {  
5 G" C+ g  q0 K7 t( [              switch (substr($v, 0, 2)) {  
: a5 f( o! ^& _4 d* g8 J, d                  case '+=':  ) e; S0 }. e9 y9 v/ O
                     $v = substr($v,2);  
3 s3 ]7 C% W% `8 j# A8 {( ?# U4 ?                     if (is_numeric($v)) {  
5 G- M; T8 Q6 a  A0 ?                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
" X( ~1 k8 q/ @- T, `6 O$ x                     } else {  8 O" S2 Q/ J2 y0 x, R' l4 u1 X! A
                         continue;  + T, j: a9 X- E  i8 M( d2 c
                     }  ) j0 Y8 R5 w: [% e2 o% i- N. f3 }( M! k
                     break;  
; H$ N% ^0 ^4 V# w/ x                  case '-=':  ' ?  F* v7 z2 \8 p6 N4 w6 O- _
                     $v = substr($v,2);  
( ?2 K" [# `9 k, Y% k  r( A% ]9 j. V                     if (is_numeric($v)) {  
; ?/ H2 ]5 f. R- S  y+ l                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  2 c6 _, x" u/ O; A
                     } else {  " K( C/ q3 O* \5 _- u# s
                         continue;  
9 k3 d. n- I! u# X3 m: K1 h* h                     }  
" n/ X2 J$ c' V* J$ ]                     break;    E( {) i$ f7 ]- \  T
                  default:  * N9 g& {, R% G: A% `; R
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ' S' l# g3 w$ M) {! S+ o( ]
              }  
# y/ R" E( O8 _. M3 a           }  
: @$ Y5 S( h. ^, H6 N. T           $field = implode(',', $fields);  " g5 v$ \* C, U, v3 v- [
       } else {  ( k- Z  p" S1 e) d4 K- a5 R, M
           return false;  
1 x6 E- H- v; B- S  c3 [& V       }  
4 d( \6 W8 S# ^- S6 o& }4 F8 L) J7 T       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ; D* M% o  p- b3 {
       print_r($sql);  
  D3 |0 K5 m4 `* R& K: o       return $this->execute($sql);  
1 k- `( ]* c+ z# y    } & C6 `) _0 `+ \# n4 H( P
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
6 v8 N8 e2 S7 ^' {# J/ v' l$ p% n. \5 O# k2 e9 Y& G' m
攻击测试:5 B9 q/ f* c& I* O( a* T' y& j
测试地址http://localhost
& f. F: O$ c2 |4 e! w9 h  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
/ |( ?8 i7 f" q
: y3 J5 J5 W% N 0 U2 e& _# X5 Y. f$ {# L) G8 U) P

$ w* `0 l8 t& S3 Y% m( ~
* A( }1 d% y2 I3 r0 C$ i: T7 U# g- v: P, j6 ^5 l

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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