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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
5 ?, S1 P) L) z. ^1 f( m漏洞作者:skysheep
! M) s' {- p' c分析作者:Seay4 n0 V% K9 p, W" I) f
博客:http://www.cnseay.com/
" J6 N5 e( l; J1 s漏洞分析:) J6 c1 b& B, J3 w9 s  B$ B
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
5 E) K4 C8 }. L0 A
0 J6 `! X+ z! x. M: s
1 G1 M; q% f9 C+ G; V' E   I9 P  X7 v; r5 ^" f
public function account_manage_info() {  & z/ w0 B. I3 H3 K
       if(isset($_POST['dosubmit'])) {  ( g" ]: t/ V, l) @8 G9 X
           //更新用户昵称  
/ j' d7 V* P2 ]4 ], C" q           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
8 `% ]. {, D( I           if($nickname) {  ) F1 S+ o* O" Y
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
0 h6 X$ @! ^& D: q+ j              if(!isset($cookietime)) {  
0 w* J* \1 Y/ {8 t! p& x7 y- \5 j6 Z                  $get_cookietime = param::get_cookie('cookietime');  / L- }  N9 S; x) E5 O$ v
              }  - @5 k7 ^2 t* X& L) X
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);    D) |7 n( g" }
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  0 O8 Z3 \; V- e0 P5 W
              param::set_cookie('_nickname', $nickname, $cookietime);  
* C, K$ |) A% \: q- k, u           }  , T# ^+ Y& t7 F4 N+ v
           require_once CACHE_MODEL_PATH.'member_input.class.php';    U) q6 q* M& _0 z; a
           require_once CACHE_MODEL_PATH.'member_update.class.php';  0 }5 ?8 x" h: W
           $member_input = new member_input($this->memberinfo['modelid']);  : P9 q. e" t& g
           $modelinfo = $member_input->get($_POST['info']);  
9 n7 `. X$ K  w, ]4 w" \) @           $this->db->set_model($this->memberinfo['modelid']);  + O/ {& {; Q5 k1 h% u
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
" z7 o" W, G* Y8 d           if(!empty($membermodelinfo)) {  / X4 C. J0 S, Z# N: ]2 t* a6 j) A
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
; n6 ?& K; @/ ^6 ?           } else {  / q  T3 M+ X$ K
              $modelinfo['userid'] = $this->memberinfo['userid'];  $ V9 X# Z9 b, P+ ]$ |7 x$ T! Z
              $this->db->insert($modelinfo);  
7 ^" O$ C" _/ N6 [* _           } ! j! l5 Z  b" v/ N+ }0 o' p
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
/ Q0 L6 o$ E! M  \& [" ]3 \& U# e在\caches\caches_model\caches_data\ member_input.class.php 文件中:
% }: M) K/ P& k5 z" a- n* M0 P: [4 g4 f* L+ F; }* F

) W7 W/ l4 y0 J3 n, }- ?* j. ` 4 u/ ~5 g0 K7 @# U
function get($data) {  3 _- |8 ?. g7 s# t; A# Z
       $this->data = $data = trim_script($data);  
/ l8 t1 G) {! E; y* d       $model_cache = getcache('member_model', 'commons');  ; t$ ]- X4 A! L) c1 G4 ?! F
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
- D& T! G! d5 U( |3 c       $info = array();    B/ h) a6 J$ r/ ]9 i, ^
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
. Q: [4 G' @* b3 u  v# b' N       if(is_array($data)) {  
# Y9 ]( k+ b7 d+ L# x5 u; A           foreach($data as $field=>$value) {  # `' L% c! T8 {+ ?  m. u5 u
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
0 A9 y! j) w1 U- n3 k# T, y, ~0 ?              $name = $this->fields[$field]['name'];  / v; @) @& f# V5 e& m; X
              $minlength = $this->fields[$field]['minlength'];  # f8 u# i( p& u* x( U# R! Z  Y
              $maxlength = $this->fields[$field]['maxlength'];  
* J! c4 ]* I) ?; x* w; R6 |              $pattern = $this->fields[$field]['pattern'];  
: R! L% @$ j7 L: ?* b( k0 v              $errortips = $this->fields[$field]['errortips'];  
9 t! K5 }6 b$ q. O- ?              if(empty($errortips)) $errortips = "$name 不符合要求!";  
9 T/ M$ F- l* V1 Y; f              $length = empty($value) ? 0 : strlen($value);  9 w6 B: U9 O/ a7 j- c$ ?. I
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  0 k: n: m+ X! m' D5 o
              if($maxlength && $length > $maxlength && !$isimport) {  0 b7 I" `- M" }
                  showmessage("$name 不得超过 $maxlength 个字符!");  
, d/ a' q) Z: Y, C/ c+ ]7 E" [+ z              } else {  + W, X  g$ E2 @- E
                  str_cut($value, $maxlength);  7 a) P! z, C4 v0 @( C& k+ h- t
              }  ! R/ e- D1 L, X3 d* s! N2 x. C
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
- B+ z8 F$ J6 A2 `) i/ [) @7 m                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
) g# f0 Q/ E$ f; n4 N              $func = $this->fields[$field]['formtype'];  / v: Z) V% A1 M" K
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
' h2 }& G; w* c. c7 a2 a5 ?, R              $info[$field] = $value;  
1 O( d' x7 t$ W. m4 b* L# s           }  
% ]+ ?$ w2 ]- o3 c' ^/ a       }  
$ _1 ~* v& I3 A- X- Y5 ?' D       return $info;  ) B6 }. t0 ]7 j8 l
    }
: c$ k8 I  m/ ^+ j1 D0 }trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
2 b& a& y1 Z7 g8 Q: e4 W; y6 Z* M% h5 n5 G) D, s
再到phpcms\modules\member\index.php 文件account_manage_info函数5 v9 k' A& `2 |! \+ [1 G
过了get()函数之后。" w( I2 _" K, ?- b! k
, h$ F( X& f, R& M" l0 m& K
5 k5 U# M9 j( I' |  U! O- X6 \
$modelinfo = $member_input->get($_POST['info']);  / C2 ?* e- b6 N! n. j
           $this->db->set_model($this->memberinfo['modelid']);  8 {2 i1 D# j: m* j: N1 z8 u
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  7 p1 I3 w' J# G  m8 Q
           if(!empty($membermodelinfo)) {  * R" s- y3 b+ S; D/ O+ y0 y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ) Y1 r. E( c% f' D" A) t6 v9 K
           } else {
- W: N% r. ~0 `; A2 [直接带入数据库,update函数我们跟进看看# C6 t8 ~& i2 j5 N3 A

: p) N5 u4 D, N! { 0 @- F7 W4 v/ q
public function update($data, $table, $where = '') {  
# f+ M, ]4 h4 c& w' H       if($table == '' or $where == '') {  
5 d0 t- b5 t7 g2 ]) o, O           return false;  
) T8 G; l5 s# R4 A1 X       }  
+ z3 }3 W/ d! H" ~6 @       $where = ' WHERE '.$where;  
  A* L, z( M4 s2 x. h0 n+ D       $field = '';  & O- @( H9 f8 g: Y$ w) w; s
       if(is_string($data) && $data != '') {  
9 ^5 S) U, B- r: _7 L           $field = $data;  
/ G% G3 _3 ]0 {. u$ @       } elseif (is_array($data) && count($data) > 0) {  
7 U0 y7 B- i0 }1 ?           $fields = array();  / W( q9 Q  u+ @  |- Q+ W9 l
           foreach($data as $k=>$v) {  * A1 G& r# ~' \- X9 a
              switch (substr($v, 0, 2)) {  
- R$ V. ^' F4 ?; g0 y+ @% ^- L9 i                  case '+=':  
8 i1 O; [) i8 g, S0 _                     $v = substr($v,2);  6 S: j) i9 F& r6 q% ]2 w# d8 F3 W
                     if (is_numeric($v)) {  8 |5 Z7 n7 w4 \* e
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
5 m6 k' d" W* [1 L8 R$ S                     } else {  / p. D1 L4 }  h: P) ?
                         continue;  / [* @, n6 m3 {6 w# ~- W9 j- G; r. w
                     }  . e4 S2 [+ P) W! t9 I$ f
                     break;  ! Z! }% K( C' E7 ~  v" G* r! C
                  case '-=':  # T$ B$ m9 W9 V8 a
                     $v = substr($v,2);  
1 X1 |, |; b1 B3 n( ^                     if (is_numeric($v)) {  
; b# h# A, z( W  |) Z5 |! s7 \. ?                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
9 s6 T( i9 ]* m; M4 T                     } else {  
; p3 r# Y4 p) I' C                         continue;  
' N, X# P! G' Z2 L$ @! d  w                     }  
* k# P& `6 h5 M0 m5 U0 M                     break;  
2 F4 n+ }2 x& t' K  I# B. C                  default:  9 @9 E) e" C* u: K
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  + B6 |% _/ U7 @& l) u" \& d9 \
              }  
7 I! |5 w! d3 L" X           }  1 z, @3 R/ ]8 V. |4 D7 C
           $field = implode(',', $fields);    s) \0 _$ F0 t# e7 y% S
       } else {  : Y& }! T  {5 Y2 |
           return false;  
" O8 j+ ~# p; T2 v       }  
3 j5 d' ^% {+ Q; O       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
8 S2 K- g  B0 ~/ }, P  S       print_r($sql);  
" c% M. B/ p: @4 c+ v" ^       return $this->execute($sql);  
  t- d7 S4 R( x) M  B, V9 Y3 V    }
% A9 K# y& N; g6 u从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
2 ]3 s8 Y5 q) N% p. _) J% B* [& O5 `! ~/ `( N$ l4 ?+ o
攻击测试:9 B; [. ^) Y0 G
测试地址http://localhost
' [% q2 e3 L2 l7 n' f  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句2 f3 g0 V+ ?$ f
7 {  h) b% C( e! j6 b! L. ^

& z7 a1 |# v. b+ a- @4 n% }+ V, k' Y1 |

! i: y4 G+ e! I! \' E  j+ [5 `1 C5 V- p; N( T

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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