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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
! v: k2 L8 E) y4 V2 V漏洞作者:skysheep
: l4 j# V& f) K+ a. {, Q分析作者:Seay% w5 M9 Q+ ^' E
博客:http://www.cnseay.com/# B; H' L1 B6 Y( i4 {* u
漏洞分析:
0 P7 B2 b1 [1 ^0 \8 \$ [. p  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
3 y$ \. y3 C/ f1 l2 N7 L4 j! ~. t" h6 P3 u

' i; A* [, ~/ g- C4 M8 s  M$ B
, ?6 `) }4 A, N. x6 Q7 Vpublic function account_manage_info() {  : U% O- _; @  T$ E: X+ u% H6 |  z
       if(isset($_POST['dosubmit'])) {    N& z6 g/ @- \4 Z7 S! X
           //更新用户昵称  
0 P5 O# }% z$ t! Y2 D           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  , n- X. U9 y3 t; V  C7 Y* F& N
           if($nickname) {  + w5 Z  U3 f' M) @
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
. E9 X+ A0 `; {7 G- v              if(!isset($cookietime)) {  $ T+ |8 y1 i, Z
                  $get_cookietime = param::get_cookie('cookietime');  ! s( u3 g! G8 C% ~+ G- H9 h) U$ f
              }  
/ Q( y& f, Q$ y# t* q              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
' y5 v2 L! V: |4 l: ^              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  ' M* P" X' f9 t5 H
              param::set_cookie('_nickname', $nickname, $cookietime);  
) R1 u9 {3 {5 C3 h9 q           }  ) O2 R0 x' D8 S9 j& r
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
( s8 x- N% t. c. O" n& X6 A8 ]           require_once CACHE_MODEL_PATH.'member_update.class.php';  8 a  W2 R9 R- k& V
           $member_input = new member_input($this->memberinfo['modelid']);  $ y1 A$ B6 }& |9 R
           $modelinfo = $member_input->get($_POST['info']);  0 Z9 K0 ~  S7 r5 Y0 T# I* ~" w8 z
           $this->db->set_model($this->memberinfo['modelid']);  
$ \( G2 j% |, T( B5 P           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  . ~6 a" E! c  k9 T9 |
           if(!empty($membermodelinfo)) {  # b, s! ?' f2 I/ \: N2 s8 u
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ' h& e5 |, Q" k; H3 k( b) ]7 f7 @- A# I3 I
           } else {  
3 S* x; ^( E* T% u0 v  }              $modelinfo['userid'] = $this->memberinfo['userid'];  3 l* I, y/ F1 ~0 z3 W- G
              $this->db->insert($modelinfo);  3 Z: n% q9 j- q
           } ) ?- h* ~( G/ o$ |. L3 {
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,2 m. Y1 e: a7 l* C. I5 p, V! W' C3 G& V
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
  F% i" t) _2 F3 W. L
% n: [  k+ u, {5 `9 ^3 R6 f4 w9 K: \6 ~' F. Z, y1 \9 L, M( O1 H
  _6 x, H" y% E: }% w
function get($data) {  ; ?; j: J7 ]1 ~8 J$ `& q8 N) }+ R
       $this->data = $data = trim_script($data);  
. o4 E* N. Q; [) T! p       $model_cache = getcache('member_model', 'commons');  
2 N" B# s" _( N& ?1 T7 K7 {       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
! a9 e- C: O& N% n       $info = array();  
1 n8 M6 }5 n5 {& L6 V       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
/ q/ R- A. _  i$ u. y( C; k       if(is_array($data)) {  $ a7 T' z) q8 U6 F& s1 e
           foreach($data as $field=>$value) {  ; v0 I" q5 Z3 z
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
1 b; ^) Z+ A! Q* N+ g3 ?: x              $name = $this->fields[$field]['name'];  1 `/ D4 V1 q4 F$ G6 s7 ?
              $minlength = $this->fields[$field]['minlength'];  
7 d5 `7 J, J: y0 Y4 `6 w              $maxlength = $this->fields[$field]['maxlength'];  
5 Q! V* a. c' c; C5 r              $pattern = $this->fields[$field]['pattern'];  
9 @* F- h. o* @5 Y              $errortips = $this->fields[$field]['errortips'];  
' D: U' w% H5 c" w8 n! f              if(empty($errortips)) $errortips = "$name 不符合要求!";  
7 _+ {: Z3 x6 C              $length = empty($value) ? 0 : strlen($value);  
4 Q' l+ ^  i# `              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  / r6 d3 z) D1 c$ j: w
              if($maxlength && $length > $maxlength && !$isimport) {  
3 z1 f; L5 k3 j$ U9 T                  showmessage("$name 不得超过 $maxlength 个字符!");  
4 V# ]0 E) G  P( q" q              } else {  
0 n& {# y2 v5 A" @" |, e/ B3 |, G                  str_cut($value, $maxlength);  # Y4 \9 [7 g9 S0 `3 g
              }  
4 V8 Y4 Z0 E9 P  U1 R" D& C) d              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
9 i" W' R5 o7 C' @, ]0 X3 J                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
' E$ Z: s+ C+ T              $func = $this->fields[$field]['formtype'];  2 {) F1 Q! F5 w8 `& e
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  4 E$ M$ u5 o6 |3 h! m+ l2 y
              $info[$field] = $value;  
- F: W& m" ?! o, l9 Z# G% j           }  ) I7 F5 I$ C* t' S7 ]- e( ?1 a0 ?
       }  ) E& x- O# u, ~* Q$ K) I
       return $info;  7 i6 `, W- n- k9 n" a" A  p: G
    } , y8 z3 b' X# B2 y: Q. k1 H( m5 x6 ?
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,# K' F4 `% r5 f$ v
# q; _+ m& u9 |7 R; P, F
再到phpcms\modules\member\index.php 文件account_manage_info函数
5 J! w; m. h4 q) Z, q' L' s/ o$ ?( ~过了get()函数之后。% @6 E- u& @  m

% H& q" X6 w' Y2 r2 Y / Q5 y5 i( g- `* |5 D7 |$ I
$modelinfo = $member_input->get($_POST['info']);    S* Q! h- Y: f6 k" n, _
           $this->db->set_model($this->memberinfo['modelid']);  
' p6 l4 a8 r5 H           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
0 ]3 @9 @! K# s/ d, D* i           if(!empty($membermodelinfo)) {  , V* l% Z: h$ ~+ p8 l! o) m  y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
3 _. N' Q" |1 @1 G           } else { 8 g) b7 |9 F. O* ]6 X4 {, b
直接带入数据库,update函数我们跟进看看
& r0 z! t- {7 N4 h' y
2 ~% ^1 Y& H8 a6 H4 I* o : p7 g; B9 F. d4 N9 y
public function update($data, $table, $where = '') {    H! ~" q/ W5 w/ e
       if($table == '' or $where == '') {  " b% e8 `+ a! \- I& D
           return false;  ' H9 w) _9 |# m9 [6 J/ T
       }  
2 S# N" K8 ~5 g8 i       $where = ' WHERE '.$where;  ( m1 A& T% u; F2 I) r4 |" c/ H
       $field = '';  
* U& a1 j4 C6 Q& F; x$ e       if(is_string($data) && $data != '') {  
% i' B4 f& S8 `$ y           $field = $data;  
, c3 Q2 S' f/ M4 P  H1 r+ A       } elseif (is_array($data) && count($data) > 0) {  ! |, b: l6 a3 |  r' l( h
           $fields = array();  / {+ t7 i0 Q' o- M3 o
           foreach($data as $k=>$v) {  
3 n( G3 ^" \/ V; ^+ h% e              switch (substr($v, 0, 2)) {  6 I& l$ _" L1 C
                  case '+=':  9 @8 x% \) D) G% d( w
                     $v = substr($v,2);  
; a0 Z8 Z: o* }3 v) H6 [                     if (is_numeric($v)) {  ! w3 |* Y4 V) ~. Y8 [
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  0 F5 N) L8 ?; F- E: a
                     } else {  - G# N! n0 w8 W: G. _0 i8 y
                         continue;  : q7 \7 S3 f5 D) n" I+ |
                     }  $ q. S/ T5 x" h1 m6 o
                     break;  
$ L0 G3 }4 j( M8 E4 K                  case '-=':  & |8 I3 v- ], ~) b
                     $v = substr($v,2);  6 X6 l- x* V0 e4 F
                     if (is_numeric($v)) {  2 a: r# v4 ^, }) m
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);    w* f& |" R+ [; f3 Q) q5 ?( f
                     } else {  * G$ K3 t) R1 a/ t6 t2 s9 t
                         continue;  
1 d) a& f9 c7 B" p; v8 e! Y. g                     }  
8 }( v' b% S3 v/ g, ]1 e                     break;  
' E, }8 ]$ Z4 W) n+ X2 i  E                  default:  6 \. S* N# w* n4 X' J+ {
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  $ p0 q0 z/ E: l0 Q. W! @4 G# R
              }  
; a, Q8 \$ F/ Y: V+ P           }  2 O3 @+ [# y) X& C) Y6 e
           $field = implode(',', $fields);  5 p) f5 M9 O  T6 }+ v2 k
       } else {  
. U/ T; n+ e, J, _           return false;  
+ M& u$ K; N, p7 H5 z       }  
  @* M( X& p8 d& D+ s4 ?       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
: b  }  a  ~" _- t4 L       print_r($sql);  
0 J$ l3 B! U# J' ^% h6 \& U) n       return $this->execute($sql);  3 O* _! J. G+ L$ k  P0 o
    } 5 j7 M0 y( @/ f9 i
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
& N4 F" r& [8 a! B& O( _  a1 n0 C% c( o5 e, b
攻击测试:+ C3 [5 @; K& }& Q5 V! m- `
测试地址http://localhost7 t+ k, @- {$ v! q/ R2 s( S
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
5 U' s& \+ G4 @8 A$ U: a6 e
5 O9 I" j, U4 n3 K
. \: A2 Z' H9 D4 E  x. H% ^+ l' p8 C! E" y1 h

; B& Q) A- e: e. F3 }
9 R5 Q, e) ^& s5 L: Y0 [7 H8 [

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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