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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
  V/ D, U  E% }3 i1 s! ~% E漏洞作者:skysheep
1 j* [- y7 c& S+ E" H. ~分析作者:Seay4 I* B$ V2 k) S" {& v4 R
博客:http://www.cnseay.com/
: L8 Y8 P, f* H2 z7 V漏洞分析:/ E% m, e" W$ e2 R6 l6 U, e
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
  M: x" J! I2 A5 j0 J/ ?3 z# c% D8 ?  C: W* a
& s* F' Q3 \( H/ x: U9 E. [/ d1 I

3 U! }3 ^: u) X7 y1 G! @8 n6 }public function account_manage_info() {  6 n; U( D& ?) t  @# x
       if(isset($_POST['dosubmit'])) {  9 N, ^" p. s  c) |6 [
           //更新用户昵称  , A# c5 P4 {1 g3 _) p) N# s3 X
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
: f& s9 n: D0 y% E2 Z6 O           if($nickname) {  9 _3 ]- `& C# B$ p8 {
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ) o; m& |# @! a
              if(!isset($cookietime)) {  # D" H1 h* e% f8 M. c- l( V
                  $get_cookietime = param::get_cookie('cookietime');  " l2 E# p0 ]" e  a) i9 n
              }  - W$ q) a% \. m
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
, g+ H+ l  Z+ c- M# ^              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  1 u: b2 U/ A' Q8 {4 d( j# q
              param::set_cookie('_nickname', $nickname, $cookietime);  
7 Z. W# \8 N: l4 l+ T9 {           }  $ `/ [) x; V# g. P7 R' ~& E
           require_once CACHE_MODEL_PATH.'member_input.class.php';  $ {$ r1 m( q( w$ `' E* o
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
% [8 v6 M& p0 J* l9 q           $member_input = new member_input($this->memberinfo['modelid']);  2 @% o% L1 E$ X
           $modelinfo = $member_input->get($_POST['info']);  / E" s% W0 S1 g1 x
           $this->db->set_model($this->memberinfo['modelid']);  
% p7 a3 M- t+ |# k  R& h           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  / m6 c5 y( F4 k4 b
           if(!empty($membermodelinfo)) {  
4 o. C7 V- j) n              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
* s4 @2 a" B0 k3 b' {2 ]           } else {  
$ \1 B- |& W8 w8 v/ j$ s& r              $modelinfo['userid'] = $this->memberinfo['userid'];  ) v2 \1 ^; J+ o. Z! p1 B
              $this->db->insert($modelinfo);  
6 N2 F9 k6 z6 B, W% f7 P           } ; X( w) Q+ F4 u0 H
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
7 p- D  {- Q  Z, |5 D0 X在\caches\caches_model\caches_data\ member_input.class.php 文件中:: J! B, G  ~( I3 r4 @1 E( Y

, A' K4 Z& f/ ]* S! ^+ i. K) p) [$ O
3 m% ]* w5 o$ @+ ^
function get($data) {  
$ \8 c4 q8 ?  w/ a+ Z, C6 \& L% J: x       $this->data = $data = trim_script($data);  $ Q9 C7 ]8 {3 p1 E5 r+ k  i
       $model_cache = getcache('member_model', 'commons');  8 f) e% A2 @9 d: t7 R
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
  N$ n0 n1 c( p4 ]       $info = array();  ; C3 ]$ g( h2 {8 R0 }% V
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
+ h5 ^% ]8 |8 K" ~       if(is_array($data)) {  ' l3 q+ G% Z, o6 K9 [7 L
           foreach($data as $field=>$value) {  - T2 j, ^0 E! N3 a1 a* R5 Z
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  % O+ @$ z5 |. c# b* L
              $name = $this->fields[$field]['name'];  
5 Q3 O1 V2 `; d5 K0 n/ H              $minlength = $this->fields[$field]['minlength'];  ! k/ h. R& u: ]" \
              $maxlength = $this->fields[$field]['maxlength'];  
$ C, U' b* s3 J8 }% w5 ^! E              $pattern = $this->fields[$field]['pattern'];  2 E2 j/ e3 k8 `/ s6 _
              $errortips = $this->fields[$field]['errortips'];  : n2 |( k+ L% `! a8 M1 ~; z
              if(empty($errortips)) $errortips = "$name 不符合要求!";  ; |/ N: S* x( n& ~1 ^3 H
              $length = empty($value) ? 0 : strlen($value);  
* i! ]( M! u3 ^1 H              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  8 i. V& V2 B! ^3 e) ?- t) |
              if($maxlength && $length > $maxlength && !$isimport) {  8 |6 E: G: u9 Y/ c
                  showmessage("$name 不得超过 $maxlength 个字符!");  
; w4 [4 m: i% m/ Y/ k+ o! I3 |              } else {  
6 q0 {- G% e: t, ?" d& x                  str_cut($value, $maxlength);  ' Q* T+ H: G1 H  E
              }  / f& H; y0 T# U/ }, a, {7 D0 T
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! O2 R% Q" Q' ~# b) L
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
1 y4 [2 G# m) m8 R4 `% @' Q              $func = $this->fields[$field]['formtype'];  
5 T% f( A3 `$ H+ b4 J8 p( V              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
' R5 m- {9 A" o: H: K              $info[$field] = $value;  
. [5 T$ ]! L; \2 M4 V           }  
! W+ f1 _! W% j+ H' C2 L3 V' N       }  " U5 f/ ?+ _& @2 Q
       return $info;  ; E. n- Q! v5 @$ h
    } + V+ ~& b8 \4 F* u# {. S
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,+ l5 ]1 u) c# C# P" }

  o; }# \  S% E  B再到phpcms\modules\member\index.php 文件account_manage_info函数% H, L0 u: a2 m+ y* {) k0 a
过了get()函数之后。; j# Y+ L3 J5 L" w/ n

4 [' Q3 [5 |& G' `4 G" ^; i% b5 d
4 f5 g# ]9 I. @' W. _$modelinfo = $member_input->get($_POST['info']);  
' W) D4 d9 J& T$ o/ l           $this->db->set_model($this->memberinfo['modelid']);  ) k5 T" F1 V, ~5 J: w4 O* i. G# b
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  0 i* c0 [. I- [% e2 d6 }2 @
           if(!empty($membermodelinfo)) {  
7 `' y- V" q8 {4 }# z              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  / n. E$ O7 n7 f( f
           } else { ( b) H% P  ^, k
直接带入数据库,update函数我们跟进看看, l6 R) [* b% g8 ?4 {! N, A  k

" C% ~9 \6 A6 V- e/ A9 d" ` 7 s* g1 y5 E, N$ V
public function update($data, $table, $where = '') {  
) T' Y& j7 H0 I% F9 y       if($table == '' or $where == '') {  & w, Q1 y2 s' c4 B1 Y  Y+ r* B$ e
           return false;  / v# u* u: T2 R5 u1 G
       }  : A+ v$ o) G5 F8 d7 ^) w, C' {
       $where = ' WHERE '.$where;  
( f1 l1 T# ?1 L: O2 H1 r       $field = '';  
  H( b* O  ^) n5 S0 k       if(is_string($data) && $data != '') {  6 @  C. q8 W+ `6 j: S1 Q# i: [
           $field = $data;  
( T3 B! t! o' r6 {' Y" j& C       } elseif (is_array($data) && count($data) > 0) {  
) J2 Q" ]( |. t+ R5 A           $fields = array();  
1 M4 Z5 ^. \7 [           foreach($data as $k=>$v) {    @+ v# T# q$ x7 _" S; Z; l
              switch (substr($v, 0, 2)) {  
2 c% T. l4 i1 W; k                  case '+=':  
  B3 P( z4 p- b$ \/ i' w) Q" \+ r                     $v = substr($v,2);  
, X0 e: C+ M' ^5 ], A9 n                     if (is_numeric($v)) {  
: X& |) j* }; a' T5 q# h9 }                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
& P. V$ p2 [2 `                     } else {  2 B1 v. `- T, T% M/ ?' N
                         continue;  
3 i) A# P7 K( ^  O* B2 e9 [$ Y! l9 z                     }  , J5 D- |( ~# Q/ H7 p! Y% K1 \
                     break;  
8 g1 b$ Y# a0 n, |" e% L& \                  case '-=':  
& D/ F$ n& Z  {& U4 J4 n& s                     $v = substr($v,2);  $ M6 \- ~7 P" n# o. E- X" L
                     if (is_numeric($v)) {  5 X# ]1 o1 O& S
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  ) I( m8 ^1 |# h8 j9 e6 u+ }
                     } else {  . p- Q3 l* n/ s' J* A
                         continue;  0 t6 f/ Z8 f6 _9 r4 H2 k* z
                     }  
! Y! d& p1 r& s! C2 ^                     break;  3 z+ ?. `# j; b
                  default:  
7 q+ L; Q3 V! ]. k7 d5 c                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  , O) S2 `. u- P. l
              }  
+ O% s6 r0 v$ _7 O% z           }  
" p! x  @8 c7 ]! f  Z           $field = implode(',', $fields);  9 `* O) ^9 `$ n2 j% T- i& f9 K
       } else {  
7 d* Y/ D  W# S) W( B           return false;  8 {" z7 Z8 s8 X- [. }
       }  
$ o" K$ d) \" A/ r; B4 n2 Z/ q! g1 v       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
" a- T6 Z9 r) A( I$ n, Q7 L       print_r($sql);  * Q# D9 f7 `0 v  a
       return $this->execute($sql);  
! U6 V; c$ p1 m& E, I    } 2 i+ {; o( H1 M' Y6 }$ y
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。1 W9 f  j( f) B! l3 W1 F, k* L: l! J
1 {! N$ ]* z2 Q! K8 f' K0 ]
攻击测试:0 H/ W/ O9 H" J0 V" d
测试地址http://localhost
! b& v8 O9 u: g6 {  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
5 {% }7 H8 T- @; E
; Q7 I4 q' H; O7 o$ E" A( i2 J
( G3 C, s5 Z" ]: S% t
' U$ T2 P4 X/ D. x& t, G9 Z
: U2 \7 j( m8 f; \" p/ A0 q& S5 u- N+ y( o6 ?* I4 E

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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