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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
- z1 Z; R5 F$ t3 r5 J漏洞作者:skysheep5 u6 U1 R$ t" ]9 ~% _% ~
分析作者:Seay# j3 W- |' s: k0 P
博客:http://www.cnseay.com/) W) \2 E! n7 P* G  S# X3 ~. M
漏洞分析:2 o- ^" H1 Y" \$ L1 ]# |" R
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。' M' f  @4 h% w! \# y* _
# H* c6 M  R9 I' t& L6 Y7 N  Z9 Y

/ J- u  w' t0 F; I
* R, g4 Y, W: p' `public function account_manage_info() {  + N: A: j8 Q/ z. ~5 ^
       if(isset($_POST['dosubmit'])) {  - i9 x' J! `& {, Q: O* Z
           //更新用户昵称  9 T3 G! o3 X, c& P9 v. J1 c
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  + ~. k. X+ A/ u
           if($nickname) {  ! B% k% E5 e6 q
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  4 K% R$ u3 T& Z
              if(!isset($cookietime)) {  + y0 \+ `0 B7 e, k% _
                  $get_cookietime = param::get_cookie('cookietime');  , ~- ]9 G1 t# s- R' ~- [9 E4 e
              }  
& @$ d. s6 P% j  O1 L              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  " }! ^% F+ @) w% l$ X2 n$ w
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  3 J9 \4 j7 Y9 ]7 I
              param::set_cookie('_nickname', $nickname, $cookietime);  
2 `2 ^& m/ S! h. I$ E           }  
, x* m2 s: a4 i8 \6 d/ O           require_once CACHE_MODEL_PATH.'member_input.class.php';  
' L% D( V2 }4 v/ S" c           require_once CACHE_MODEL_PATH.'member_update.class.php';  
% [+ g: R/ D! E$ L8 G7 V/ t           $member_input = new member_input($this->memberinfo['modelid']);  
( g2 h& d% R8 y" T0 F           $modelinfo = $member_input->get($_POST['info']);  
5 X9 U& r+ n. ~0 B+ [0 F* S6 z           $this->db->set_model($this->memberinfo['modelid']);  
- E2 Z0 O( K" {% P* ?. A/ X. `0 {           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
$ H  Z6 q" ~7 @. ^1 y! k+ @" w           if(!empty($membermodelinfo)) {  
- A+ b! K7 `7 o+ F. G  c; b              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  : G; J& }, {( @
           } else {  8 }9 V$ L4 `4 Z. R
              $modelinfo['userid'] = $this->memberinfo['userid'];  ) y( V6 S8 v# R/ i
              $this->db->insert($modelinfo);  + C- ]  j" I1 R: `9 ^! y
           } " N( w: T2 K- _0 Z& K
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
1 Z5 f0 }+ u7 s# l在\caches\caches_model\caches_data\ member_input.class.php 文件中:4 ~) p# ^$ @5 m; j5 S) s5 [

) d. k5 O" J) I3 y/ V! z" O( p. R' o; n

) n+ p2 P" e9 Z3 V* b' h. qfunction get($data) {  
* Z; j9 _1 i$ N% B2 Z8 b       $this->data = $data = trim_script($data);  " Z+ s3 f* A- X: \: y, h
       $model_cache = getcache('member_model', 'commons');  1 W0 e7 ?& h0 m& V- a+ |5 v
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  3 A0 W! F+ {* o7 M7 h, i
       $info = array();  
5 o  X- ?1 K! p! N6 C% l       $debar_filed = array('catid','title','style','thumb','status','islink','description');    Y  ?4 o% D2 y) h  t  B5 K
       if(is_array($data)) {  
+ v6 R! T1 ]# e4 e- ~2 W7 E           foreach($data as $field=>$value) {  ) ]  l: b( R4 S7 s* S5 Z8 U2 \' e
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  9 K: i! G" X4 {
              $name = $this->fields[$field]['name'];  
1 B* D$ l9 k2 o" G5 I9 m  [2 q              $minlength = $this->fields[$field]['minlength'];  * I! y  \1 R" p8 X  J! d
              $maxlength = $this->fields[$field]['maxlength'];  
. a6 `2 n& V8 M6 H              $pattern = $this->fields[$field]['pattern'];  % s: U. X: s: R: }% d* N
              $errortips = $this->fields[$field]['errortips'];  
2 e# F6 x* `# n0 {) w8 ?. B  K( f              if(empty($errortips)) $errortips = "$name 不符合要求!";  
- J. Z2 d& I1 a4 T3 K0 x              $length = empty($value) ? 0 : strlen($value);  $ p2 [' L: a! ]" [* m. Z
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  * U( q! @- ]* Y" C: m1 G
              if($maxlength && $length > $maxlength && !$isimport) {  ( I% Q# V, F( n' r
                  showmessage("$name 不得超过 $maxlength 个字符!");  
. E- R9 G! @8 i- W% V              } else {  
. K1 z" x" P4 n5 W4 ]8 N# A1 J                  str_cut($value, $maxlength);  . X" k. q& J, B  s6 s
              }  
# ?! p; N+ o2 I              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  : D$ a. e+ h9 \0 d6 c$ p0 o
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
$ I4 j. u! j1 P  O/ @( j8 l              $func = $this->fields[$field]['formtype'];  1 C; p& n0 i+ s: i
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ! n7 D6 r. m0 L' z. J9 P, o/ Q
              $info[$field] = $value;  
! b( `% D* c: V9 r& |' X           }  
; Q; k& y/ `4 a2 D8 v$ U7 a       }  
& }+ o( M6 C/ G/ i       return $info;  
, ^2 C: ?: {6 p    }
- y2 a' S5 ]+ b) ]: j2 V, ~5 ?0 dtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,) k+ H; z* U! G, H  X* y
0 A6 I3 `$ i6 G- h
再到phpcms\modules\member\index.php 文件account_manage_info函数
' o- S, ~4 t2 G4 ], I# P  a过了get()函数之后。
; _! ]& u5 C# c6 C
; y' M& n: Z4 y' P ) e9 R* ?6 ]. B
$modelinfo = $member_input->get($_POST['info']);  % ~  ], G8 @+ q7 g$ }
           $this->db->set_model($this->memberinfo['modelid']);  
1 ^( w5 l7 t- Z, i" {( ^  s           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
5 i9 u/ s. z3 U9 ~! c           if(!empty($membermodelinfo)) {  
9 K/ S: W3 ?) m" ?              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
! p& m/ J$ P) M' m           } else {
0 r+ m. _% z8 @' f: d$ [直接带入数据库,update函数我们跟进看看
; @  a7 c9 t+ F( r​4 {1 x0 G3 @9 X* ~1 ]% X5 ]1 p

% ^* ^1 O& v1 F1 qpublic function update($data, $table, $where = '') {  
. c) F% r* [! z: ]9 z       if($table == '' or $where == '') {  
/ S4 C6 b( K6 l: ?           return false;  % G* {& K1 t) ?) u0 A
       }  5 @9 D1 N$ O6 J: L( B5 r8 Y: X& d
       $where = ' WHERE '.$where;  . D4 w: V. F3 S# F1 B: N# t
       $field = '';  
3 `% L6 l" i1 e1 \; F       if(is_string($data) && $data != '') {  & ^  v" ^: ^7 E( A7 r0 V
           $field = $data;  
* x2 l( J" V6 o: M% S       } elseif (is_array($data) && count($data) > 0) {  
/ p+ m, Y6 o" ~9 w1 q           $fields = array();  
; Q: [5 i, A5 ^           foreach($data as $k=>$v) {  6 P: O, U2 W( m# Y  ?# p
              switch (substr($v, 0, 2)) {  + {8 Z3 I/ T) q
                  case '+=':  
6 E! Q! F8 D  E0 Z" W                     $v = substr($v,2);  
; [+ ]* {% Q0 u0 f" c                     if (is_numeric($v)) {  
% z. b7 E: ^) X# X3 E' M                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
) Y" Y, V8 H3 d+ j$ e8 g                     } else {  
' y  ?1 [8 q: Z4 {6 f: B2 h& F                         continue;  - k% t8 @$ {3 a
                     }  
1 ^8 X# ^  Q5 }                     break;  # y# C7 Q+ X+ M  _; E3 y
                  case '-=':  
4 H, _. p& L3 @; s) ~1 _! D/ x                     $v = substr($v,2);  
$ T7 W" E: Q- G6 b4 V, E                     if (is_numeric($v)) {  2 S5 c5 B0 i" l0 K# l$ L5 c0 i
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
& M0 P6 R2 W' z' N! P. \& F/ K. J) |; Q% k                     } else {  
9 {" l9 ~  |# S: I' I7 R. C' B; S0 \                         continue;  ; J* N+ @  s/ B7 L! M/ Y( M% N4 V
                     }  ; \* j0 Y# f, @! Q' [
                     break;  ! C! o  _7 T6 T. z! x) E  n
                  default:  * }% d9 [7 C) T7 a+ k
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
1 R+ K% _- L1 }. W0 n+ K              }  * S0 I0 v1 Z) g: A2 h: s
           }  
6 v* I  O2 a' q6 O% [           $field = implode(',', $fields);  
! {/ C# b4 @( |* ~, P$ ^3 t       } else {  
" }3 p+ t* B2 o' E, C           return false;  , T$ t" W2 x4 m3 }
       }  7 N4 g+ ?9 S  V" R7 I, m
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  5 B3 b/ \. @8 c
       print_r($sql);  ' {$ S( y* _/ ]0 {- A: n$ A
       return $this->execute($sql);  
5 v+ H) o( S% m$ k: t: W    } $ c. }9 e6 U/ K# q5 Y4 J- S/ a" z- O. \1 ]
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ i& X/ a! V+ K5 y3 s. H
; W2 \# N) y1 r1 W# R) O攻击测试:
$ t; x( d1 V/ z& i5 ^测试地址http://localhost& }6 @& \2 a5 A2 O8 q
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
1 }% v; Q8 C) b1 G/ a5 W! F* P/ A4 t* R, [! Z( D

8 d0 p$ [3 T# U) \+ N$ w$ b$ S0 F( m! ]* @! e4 ?
( H! y  Y7 P  c1 N/ s% `

$ p0 |' y6 h! P) X, G

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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