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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告8 S( c0 y) b% P% `6 w/ b
漏洞作者:skysheep
& P' J8 p. M/ ?  Y) A分析作者:Seay
2 t6 z/ g. @& N+ b& K, q# N. k$ w: G博客:http://www.cnseay.com/
8 s/ D* J: F" u- }7 a$ o. _漏洞分析:) ]$ q2 V6 F1 O! Y! i6 X/ W0 s1 i
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。% \# S* O7 ~& t* f4 Q

( h' v4 {; {# l* B; |
/ S3 `4 N7 p  E( g
$ q4 x- c9 k7 k) q1 Cpublic function account_manage_info() {  8 D- j' q& R  t0 b/ r0 S' L5 {
       if(isset($_POST['dosubmit'])) {  
! E. M$ P9 I3 ]7 Q% |! ^           //更新用户昵称  
. B! L  b/ \7 O: N5 N           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
+ T9 y- H! W6 t# d; u7 g- M           if($nickname) {  
/ _6 j1 K" J- l              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
$ c- e6 R! ^3 E+ e+ q( F/ _# q7 R7 _9 m              if(!isset($cookietime)) {  
8 `" ?+ v& W' j2 F5 M  o, o. a                  $get_cookietime = param::get_cookie('cookietime');  / [% \5 C+ G& g& n
              }  & Q( @* k% N) M* A5 a3 x2 e" G& c
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  # A* `  r8 _/ K/ ?& T
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
: X6 L/ I, M" q( e              param::set_cookie('_nickname', $nickname, $cookietime);  
* r, y. G- q# k           }  4 T- V8 d3 N( E# H, b  [5 J! m& w
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
4 f2 W4 [; c) L2 Q           require_once CACHE_MODEL_PATH.'member_update.class.php';  ; |% i/ c4 }5 A8 ^
           $member_input = new member_input($this->memberinfo['modelid']);  4 F# e; `, D0 q/ n
           $modelinfo = $member_input->get($_POST['info']);  
+ q; l: N$ _( v           $this->db->set_model($this->memberinfo['modelid']);  , _0 Z( A$ C! g- T5 I0 p
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
+ S5 l- N$ b3 J5 l- c' |           if(!empty($membermodelinfo)) {  2 Q! R$ @7 `) _. ^9 p/ d$ K( E+ `# D
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
6 q9 s; l% A/ j; I! q  q           } else {  7 Q) K, U( E0 g# J
              $modelinfo['userid'] = $this->memberinfo['userid'];  
+ g% k5 C; Z0 y  M              $this->db->insert($modelinfo);  
, F/ t) @6 X; ^9 V, O8 A: T           } ' O4 i- N: y7 A, g# z$ f+ [
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
! ]7 P' J4 T5 D6 ~4 O* h在\caches\caches_model\caches_data\ member_input.class.php 文件中:( a' `4 ^! q" G* O  e/ T+ `
* E& o+ l) a. b/ q

/ ?3 j8 {% v+ Q% k! u   f8 m+ ~) q+ I4 D, g
function get($data) {  - ]' D* r% u& u
       $this->data = $data = trim_script($data);  
: Y) w, U* Y% e& o7 A       $model_cache = getcache('member_model', 'commons');  
; g3 R0 {3 Y6 d       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  1 S* h( {$ _4 ]* V8 r) a
       $info = array();    q2 M$ D5 e7 N- ]& w
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  ! J$ z$ A$ U; p' n9 E, P* C. q$ }
       if(is_array($data)) {  
. z' w5 k# ~9 h6 O( b  O           foreach($data as $field=>$value) {  
1 G. z# U9 ]2 o2 \, G, @2 U              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
. ^3 y  z+ I# e' n! c  M              $name = $this->fields[$field]['name'];  5 |( K2 P3 r& s3 j
              $minlength = $this->fields[$field]['minlength'];  
5 w7 |) `, h- {# i6 {9 z              $maxlength = $this->fields[$field]['maxlength'];  ; p, l9 r, _; V0 z- w3 w! o
              $pattern = $this->fields[$field]['pattern'];  
& x7 M5 g. q" ^: A, g              $errortips = $this->fields[$field]['errortips'];  
: J) N+ M6 l$ t" K- K; I7 n              if(empty($errortips)) $errortips = "$name 不符合要求!";  
  ^+ _# b; g0 x              $length = empty($value) ? 0 : strlen($value);  
/ l- @  y0 U' B! t! `              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  6 A  ^; h, Y! v- O
              if($maxlength && $length > $maxlength && !$isimport) {  
6 X" Q1 l/ G) p8 m" a                  showmessage("$name 不得超过 $maxlength 个字符!");  
1 ]; Q% S3 u# `              } else {  3 Y/ Y' L& G) K: {5 Z6 C4 j9 W
                  str_cut($value, $maxlength);  - Y- Z# z* f& K. ^0 s
              }  / Q2 c% ^, R# x! x2 Q2 c6 J2 L
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! }( {% h- W* V, g5 K3 ]- Z
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
/ K( s: B6 J. W# a+ T  j2 I" Q              $func = $this->fields[$field]['formtype'];  
" n3 r0 ]7 O' U* x: _; J              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
2 ^% x# s7 l& O              $info[$field] = $value;  
! Z& K  D# z" q) C! x: @2 Y           }  
9 o3 H- T( P* N  D1 e       }  
/ A: f# d+ j0 N/ B" N       return $info;  * Q% F( R+ L6 P
    }
' E) M7 D2 \% n3 O" Wtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,: n; }& a; b/ v: M

/ F  z& \) i6 S. Q' S6 s* ?8 |再到phpcms\modules\member\index.php 文件account_manage_info函数; ]4 c. j% m2 j: \
过了get()函数之后。  [" J% E9 p1 e  q

/ U' {, U( b. D# n" n  O* @- r
) U  U- [* V% m6 h+ z$modelinfo = $member_input->get($_POST['info']);  ) o# [7 f3 V4 _4 v
           $this->db->set_model($this->memberinfo['modelid']);  & s" U4 I; Z2 p
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  9 v1 w/ T) `% \5 w% M2 B! c1 s# |
           if(!empty($membermodelinfo)) {  6 O8 K0 ?* _0 @& W; j
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ' M9 U) c0 r' k' }- ~" S2 n
           } else { - v1 L, X) X$ z8 h
直接带入数据库,update函数我们跟进看看. P9 ^8 r6 y! ?- u8 Y1 L
( o3 ~! Q. |) ?3 k( L

- Q% o- S5 K3 v% z+ I6 D2 Qpublic function update($data, $table, $where = '') {  $ g: s4 U, X% ^3 I* E7 B% ~
       if($table == '' or $where == '') {  & m- H3 M; `, Z
           return false;  : E7 a# U: K, x. J# M, U$ @/ ?
       }  
4 s, O/ _9 r, X: u6 K" N       $where = ' WHERE '.$where;  5 k7 v9 r6 ~, Q5 R' I/ _1 I9 ~- x6 {
       $field = '';  ) ~) p4 l0 q5 ?) O
       if(is_string($data) && $data != '') {  
: ^6 L: Z9 c+ c           $field = $data;  6 I9 C$ v5 n& t
       } elseif (is_array($data) && count($data) > 0) {  7 J7 d. n; E) K7 B# b
           $fields = array();  , P3 K( N( ^  a' r
           foreach($data as $k=>$v) {  : ~  s! F! _# z1 u
              switch (substr($v, 0, 2)) {  
% |7 M" _5 c2 K+ S: G* D, X                  case '+=':  7 ~/ S# i; j  D$ c* h
                     $v = substr($v,2);  
. M. `* b( v! m2 G, A                     if (is_numeric($v)) {  " Q1 `: ~+ }9 r8 p$ @: W7 }- t# j
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  $ ]. T- N# j. }+ o' L
                     } else {  8 R+ R4 P7 Y2 ?# Q: |+ F( e6 H
                         continue;  
' L5 o2 R0 T4 N: i% A. s                     }  
# S! {7 j  B7 l& k7 f                     break;  5 m9 i! y5 U5 T7 v7 z  `6 _
                  case '-=':  9 [2 C: D' B/ c* y: d
                     $v = substr($v,2);  
) q/ v- t, y8 G& s  p0 V3 r                     if (is_numeric($v)) {  / m, _) T/ H' |1 c
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
) O2 V8 d" v% h5 Q0 f: @# P                     } else {  
% s" V. ^4 t+ g2 y2 c                         continue;  4 n# X. E. G, \5 C' i5 P
                     }  
9 V8 x$ b% B% t( ]; o! Y7 ?( @                     break;  0 L7 k5 x4 e. z" l
                  default:  6 W  N: a8 R! t  a# v) u  v- m
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  " |0 ]& n' |; A- a5 T$ ~
              }  , x1 N7 ?8 @8 @8 L; ~) c( f7 X
           }  ) _% k" P7 S6 q* N1 t. z# h
           $field = implode(',', $fields);  
& a4 b! i/ N5 s" N4 {       } else {  % ~+ d0 {8 k, S+ K6 {& ?7 w
           return false;  
2 r5 H1 ^$ U# @6 p4 n& Z: @% l       }  # Q  p" |/ G4 z) b8 u' \
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ; y- M7 O& g9 h9 I9 L5 A4 I
       print_r($sql);  " c9 T3 U' l- ]; ~6 ]
       return $this->execute($sql);  $ D! q5 E7 ]9 T/ {& w
    }
* ~+ n( [0 E0 K9 ?" o从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
+ Y  L& d6 H2 A; ]4 Z5 ~  E
' m2 a+ q, D7 B7 `: c2 V- |攻击测试:, X$ ~: Z& T& R4 W* P# @9 j- Q9 ]
测试地址http://localhost
  e( j2 I" U: ?6 J- U1 x) I  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
6 q" B$ M) G$ {( _5 r: Q! `7 |
8 \  Y; G% N' \& F# e8 ^ / A4 E! E( Z) B& s

" [( h* F5 x9 p+ d3 C, F# Q, z
. |2 G( G# S: O) C. g* M: A" l/ u* S0 {) M" V+ o! `' ?

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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