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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告) E7 ]% F% W" w9 x: C
漏洞作者:skysheep
7 q* U% _' U& Q3 b! z& Q分析作者:Seay
+ H2 U2 O4 |' r+ v( a- @) G博客:http://www.cnseay.com/
/ K2 _$ @4 f- G# {4 i$ _漏洞分析:
- B4 c' H; C* Y2 m/ J* b9 \  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。0 w0 ?7 M: S! `$ Z  e

( {- h5 x9 T( r8 B
4 I# L; h; v4 N& M) X! s, F) T # @- Q6 U, C8 M# Q8 K: f3 k' r
public function account_manage_info() {  
/ a8 V7 h0 b3 X6 I" F0 X4 m       if(isset($_POST['dosubmit'])) {  
6 D+ c0 b6 h: A2 [2 s0 c9 @9 @           //更新用户昵称  " A9 N* ^5 b4 N+ T! f
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ' A, ]4 c+ W4 G- f4 N
           if($nickname) {  9 }: ~7 `  Q0 o) M+ _2 }! _
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ' g7 {5 C3 F; P
              if(!isset($cookietime)) {  8 i( j9 o$ t2 L) x+ Y; p* S
                  $get_cookietime = param::get_cookie('cookietime');  5 i. _5 Q4 E4 |  X* f
              }  
, i5 n! ?. S) @- T# b7 q              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  ! {$ M" |7 p& w3 n
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
5 j: f2 j  L. u  H0 {' N              param::set_cookie('_nickname', $nickname, $cookietime);  
0 R, U; {4 ^, ^) X           }  ! V* L7 j8 g2 f+ j+ c
           require_once CACHE_MODEL_PATH.'member_input.class.php';  . ~" B4 ]1 g0 ^9 D5 j/ W
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
  s( a) Z  Y6 \           $member_input = new member_input($this->memberinfo['modelid']);  ' E% ~) P4 ?0 D) ^5 \
           $modelinfo = $member_input->get($_POST['info']);  : z! |$ A0 A# n
           $this->db->set_model($this->memberinfo['modelid']);  
1 X& B3 U+ X: l% x' u2 l- {5 ?           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
$ P4 ]/ ]$ T7 K3 E7 u" z           if(!empty($membermodelinfo)) {  
5 H; a: F2 d& c+ U/ ^- V+ p7 \) j* [# d              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
, e0 W4 J7 K7 U3 A9 R7 |1 r3 B           } else {  5 ~. l2 X) r4 J4 S1 m
              $modelinfo['userid'] = $this->memberinfo['userid'];  
+ c$ C* k% O, K" P/ ~/ X- ~5 |" }; `9 o              $this->db->insert($modelinfo);  
$ N4 E' r3 u: l- B1 H/ g) |5 G! X5 I           } - i  t0 F- T% c* u) i
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
* `, U3 v! ]7 N! N  L在\caches\caches_model\caches_data\ member_input.class.php 文件中:& Y8 r8 K+ V) |# E- Q
5 n+ k# H! b  i7 w! {

* @  H. U( l* S' K  i
1 Q9 o& x4 R$ v/ vfunction get($data) {  
7 a" b, p/ O% E# o6 ~! C4 s6 N( d       $this->data = $data = trim_script($data);  $ h6 i) M& _$ j9 `' Q
       $model_cache = getcache('member_model', 'commons');    g5 h% {( o* X1 o% h
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
8 F. h3 |) S) e/ g0 t) A  M       $info = array();  1 U# _* r8 a& y) n
       $debar_filed = array('catid','title','style','thumb','status','islink','description');    Q, B6 _  f1 w5 `3 |. ?
       if(is_array($data)) {  
6 s" k  V1 q. v& F           foreach($data as $field=>$value) {  2 w5 }$ ^! t1 U) `+ w% O: j. O1 O
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  / n+ o: D( F* m, P* s0 i
              $name = $this->fields[$field]['name'];  ) I. P  J6 V) {6 {% g7 s# f
              $minlength = $this->fields[$field]['minlength'];  " @% r' K0 i, ]0 c6 z( p
              $maxlength = $this->fields[$field]['maxlength'];  
* u, X# Q) T4 x2 H- P0 _              $pattern = $this->fields[$field]['pattern'];  
6 Z: T: V" t8 a. ^% E9 a* D0 S              $errortips = $this->fields[$field]['errortips'];  0 a5 y/ f2 Q/ }" g& G! T
              if(empty($errortips)) $errortips = "$name 不符合要求!";  + i  S1 G9 c( f3 x& Z$ p( V
              $length = empty($value) ? 0 : strlen($value);  0 l: ^$ N+ L0 ~7 M% q4 j
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
5 W' u7 Z$ ~" Z. N& U& P              if($maxlength && $length > $maxlength && !$isimport) {  
6 m! L  S0 D  g5 ^/ {" D$ o2 q                  showmessage("$name 不得超过 $maxlength 个字符!");  3 J$ E1 r/ K; \0 p" K( p
              } else {  % K) }' n9 S" {
                  str_cut($value, $maxlength);  
0 c* ?- p" s: c( x              }  
8 u8 M& G+ p/ g9 I# T( ^; w              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  # p: k1 z/ ~+ x4 _  Y' n6 r
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
' B- {; B/ V0 [8 J/ M# S& T- q              $func = $this->fields[$field]['formtype'];  
* q* d) m1 B4 e/ N" x              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
: ^' G# a) b0 C8 I7 h0 ^              $info[$field] = $value;  
9 Y" r: T8 K' ~5 Q1 s* w           }  6 p  R" q5 U/ J9 f2 s
       }  
/ ^/ i, o  e4 X6 ]: V       return $info;  
& k7 x: [) u" F  J7 ^/ P5 U    }
& p$ ?7 n* h6 q" T  L- ctrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
- u" |7 l2 N, A% G$ F% G8 D0 M# ]' W& b7 B0 m
再到phpcms\modules\member\index.php 文件account_manage_info函数
6 n+ S. Y7 m( l; i% [过了get()函数之后。
; R6 I" O% G, P% L# C3 w/ v7 {. t) \& |
) ?" n: z0 H9 m2 `
$modelinfo = $member_input->get($_POST['info']);  
" K8 d+ J4 q8 Y$ l$ F           $this->db->set_model($this->memberinfo['modelid']);  
; G+ I* G9 p  S$ c7 H0 c* Q           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  # |0 P3 b8 l, @% `/ M! @
           if(!empty($membermodelinfo)) {  
8 \+ K) b  Q( ]  |              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  # B; h8 e3 x2 n' C  s9 I
           } else {
7 v2 n; r$ b+ X/ h直接带入数据库,update函数我们跟进看看( K. {( Z7 v7 K% i* i

2 F9 X, f7 d3 L
1 m% @9 y8 a6 i8 ~6 z4 C: V! C9 \public function update($data, $table, $where = '') {  9 B) j! K% _9 m1 O$ e
       if($table == '' or $where == '') {  % e- W6 F" m1 P: G+ q
           return false;  
: a: ]" S0 d4 d. u0 ^       }  
. q7 F8 e, @! \9 s4 ^( `       $where = ' WHERE '.$where;  
. F. M6 Y6 P) n       $field = '';  * f8 m4 ?2 B: }; s
       if(is_string($data) && $data != '') {  
$ N+ F# e- b1 z' h% s: U1 l           $field = $data;  + d& D3 e1 B  E; T7 s7 T2 E6 j8 P8 r
       } elseif (is_array($data) && count($data) > 0) {  
# c; o2 w9 ?% U           $fields = array();  $ z2 k0 d- ?9 F2 V8 q1 x
           foreach($data as $k=>$v) {  
- a; z; @: p1 Q4 ?3 c. ~              switch (substr($v, 0, 2)) {  
/ l' X7 [; A2 `                  case '+=':  
- W  j% v7 s& f* j                     $v = substr($v,2);  
1 F1 g2 [$ B# w9 m, Y/ r1 C' G                     if (is_numeric($v)) {  1 v, \' m5 \" d
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
2 C  Q; S" w& a& t7 B( a                     } else {  
& }5 e1 c: ^6 L& T  Q1 V& P                         continue;  " j. b8 O  @  X; U  q& V- b
                     }  
5 R! K9 k* b7 q; u/ h. A9 I& G                     break;  
5 i  m1 g, ~1 h* X$ N                  case '-=':  
: _+ n4 n/ [$ p( w& i  e                     $v = substr($v,2);  9 g4 V0 }) b- v- G, H3 ^, P
                     if (is_numeric($v)) {  
9 D" W  z9 E. ]! I7 L                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
3 M# Q& H4 z) w, t                     } else {  
0 w5 U4 W2 B* V/ m. B                         continue;  
7 j  w$ W. q, B2 m; G                     }  
7 |4 e. K' v2 ~  t                     break;  4 Y* D  V( j, l. B" v
                  default:  8 v6 `0 d8 Y8 |* o% K
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  + r6 o9 n0 K4 q3 h  K+ ?
              }  
' M2 @0 N/ K6 q6 l  y           }  % V9 m& M9 F6 v: I  ]
           $field = implode(',', $fields);  ' P% R; N2 f) E( h; ?4 W
       } else {  0 Q* C) H: A) W  y$ T7 i
           return false;  
- ]# j, ]& z; B4 _' Y) p' i1 Z- S       }  
+ ~2 V2 f' H. ]       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
7 t2 c) g. G; V3 `  m5 ~$ e/ a       print_r($sql);  
  _0 r0 p/ m# P: O/ }. Q       return $this->execute($sql);  
. `' h: V' l5 E: J1 I, K2 X    } : e6 [2 U, g+ {8 y5 r9 X& x
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。, E$ c' K  E$ ~! J# ^7 T  `, W& J

1 y# t8 V( ~  ?3 {( R- T+ |攻击测试:
3 j, F3 D- p( k测试地址http://localhost) y) R# f; x4 T0 n' ?% j
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句& O7 U- ]2 K" Z
1 t1 K1 Q0 P8 q
7 `: o, p/ R9 ?5 H5 M
6 R5 w* s+ n' [" k( W
# l- J5 ?& g7 v% f( H7 ^" I
( o( ~8 ~. Y: s

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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