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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
- C4 @) P1 S1 V" d" ~4 Z9 ^/ a漏洞作者:skysheep1 ?4 K: [# W, Y" S* L
分析作者:Seay
: o$ \, u) j" o博客:http://www.cnseay.com/
; ^: P, `  ]& I/ B* L1 |' ?漏洞分析:) e+ O1 E& s# \+ T
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。8 _8 Y4 J' ^. ]) Q: q

' L( x1 H+ T# a! o: Z- j' @1 N! T9 q3 C
$ X" f. ~( s$ m9 U$ a0 @, D8 L8 a
public function account_manage_info() {  
+ S7 u& h3 y8 @* k       if(isset($_POST['dosubmit'])) {  
$ T- M, A( D2 b+ k9 z1 r           //更新用户昵称  
& w1 L9 _9 M% c! ^! Z           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
$ l& r+ n" S! O/ c' ~2 E) X           if($nickname) {  
, k4 M# D1 L" x              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
0 h9 V+ s8 {9 S( w$ ]+ j  g; ?              if(!isset($cookietime)) {  
( A: X- U2 u# y- }& _                  $get_cookietime = param::get_cookie('cookietime');  " z9 l& P! }9 W5 \8 R% y/ s
              }  
  |8 h/ z: |7 L; ~              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  / H9 Q: Q& u& \/ a
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  / ?( v& o# r0 Z
              param::set_cookie('_nickname', $nickname, $cookietime);  
4 L2 E" r0 q' a- o0 p' f           }  1 f( Y. j% W; e! T. _6 i
           require_once CACHE_MODEL_PATH.'member_input.class.php';  5 S! V! \$ E/ ^2 P
           require_once CACHE_MODEL_PATH.'member_update.class.php';  / x8 V/ @7 \' ?$ ]3 b/ L
           $member_input = new member_input($this->memberinfo['modelid']);  5 K# r& Q3 s5 ~( H2 q8 ?
           $modelinfo = $member_input->get($_POST['info']);  
: J: I5 U% j: F4 o0 ?* ^; Z           $this->db->set_model($this->memberinfo['modelid']);  3 F: R& h" p; i! _
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  2 w2 z3 d! `7 l
           if(!empty($membermodelinfo)) {  
1 S% g& Z; J" C$ F* W; c              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  . S0 o7 v+ B0 t7 s- U0 _9 R4 m
           } else {  ! N+ ?7 U& _+ ?+ k& F
              $modelinfo['userid'] = $this->memberinfo['userid'];  
. z+ n/ }4 R& Q& F  K. M% ^              $this->db->insert($modelinfo);  
! P* |) D1 e- y! T6 G2 \           } 5 F! i7 g2 J, }& j& b
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,9 |% A7 U# ^# w0 @7 z3 u
在\caches\caches_model\caches_data\ member_input.class.php 文件中:% N& n9 E: W* r
7 }4 r: K0 f: f6 I
$ I- d# \4 b! X* ]* `
  b! y6 R( `0 @! M
function get($data) {  0 h0 G5 a7 J  R, b' c
       $this->data = $data = trim_script($data);  
/ v& l% F/ Q: A: \/ g% c       $model_cache = getcache('member_model', 'commons');  
( D& t  T6 ^' d" V       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  + C6 G2 g( Z: U9 n
       $info = array();  ' f2 F' R4 v1 G% U3 w/ U9 G. k# Z
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
9 _- R# O4 J* w2 d* {7 S: A+ P       if(is_array($data)) {  
4 y! h' i/ F0 g1 h           foreach($data as $field=>$value) {  4 ^  Q3 Z: u4 z6 g5 Q, k
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  : v8 o/ w* m. t, D
              $name = $this->fields[$field]['name'];  / O" R: U$ {% p! x* B$ L. p% y( }6 q
              $minlength = $this->fields[$field]['minlength'];  
  W8 P2 n1 _- D3 e5 P              $maxlength = $this->fields[$field]['maxlength'];  
. Y% O: A3 h  y# Y              $pattern = $this->fields[$field]['pattern'];  
% d( Q9 Q" p' V& I9 u9 n3 E. _4 m              $errortips = $this->fields[$field]['errortips'];  
4 J% [6 t! i" K  M              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; K# n* ]2 J* s4 f1 G6 J              $length = empty($value) ? 0 : strlen($value);  
: C, y1 d8 r( K# I' s0 ]              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
0 }7 L* q, E4 N& A3 Y$ e, R              if($maxlength && $length > $maxlength && !$isimport) {  
4 Z1 k6 \8 J* N+ j                  showmessage("$name 不得超过 $maxlength 个字符!");    w- N4 w5 A* r! d# M  w
              } else {  
  [& J( ?/ W! w: R( b2 o4 z- E                  str_cut($value, $maxlength);  
. h4 o& C- n+ Z              }  * J0 d6 K1 u: j+ Z! O0 i! y
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
. @' N! `8 w1 W+ Z, N0 z6 r                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
& ^+ x  t( k) p8 h              $func = $this->fields[$field]['formtype'];  
; r& J: h! O) b4 K              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
, f2 s) S1 a. L9 W5 x1 v              $info[$field] = $value;  
; N, k7 d. ]1 H           }  7 x9 g" o$ l: }7 ?% j
       }  6 K$ x2 n$ l+ m
       return $info;  
; Y9 q/ V; ~! r  O  r# b  F    }
  G- d6 b  K' Ctrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
/ v5 t: L2 q& N# }2 }" g! a- p
% `5 a: ^9 o, j% C再到phpcms\modules\member\index.php 文件account_manage_info函数$ A, ~3 F( F* Q, y6 f" a4 w
过了get()函数之后。
& N5 A! z* ^" }: @# h, s# x
% n& Q3 h: C! e- S  c4 x 7 j) F) {2 A) d5 o! I  M
$modelinfo = $member_input->get($_POST['info']);  
+ A) x* a1 a  e  B" g           $this->db->set_model($this->memberinfo['modelid']);  
# J' F0 k8 m1 N$ S2 M4 o, i$ i           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
. @7 d7 F' r5 d" E, R- ?           if(!empty($membermodelinfo)) {  7 ?! u4 _  e! P  c5 C  d3 A& y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ' R+ s9 A3 M: E7 o' M3 v
           } else { 4 Q/ D* p! D0 `# F
直接带入数据库,update函数我们跟进看看! p8 d( Q0 m* S, j9 z

8 V6 k' l7 U3 Q9 ` " J1 \( q0 Y0 P
public function update($data, $table, $where = '') {  ; B1 ?- }. f) C2 c4 u  ~; O4 d
       if($table == '' or $where == '') {  
' j# A/ r3 A1 H% f9 b2 P           return false;  
) T, z3 Q5 p9 H! m( N+ w       }  - x' @( p8 [* }8 h6 ?' `0 A# A
       $where = ' WHERE '.$where;  % a+ @: L5 W% I! L! k
       $field = '';  8 v. M5 ^4 m$ r2 b- T9 N5 r( [) p
       if(is_string($data) && $data != '') {  
5 r- ?# z  }7 [4 j" T+ k8 t) B  [           $field = $data;  
! n. E1 t* Y* E0 f4 @9 b       } elseif (is_array($data) && count($data) > 0) {  
4 R+ [, d# i  L! P( Y. ^5 _           $fields = array();  
: ?$ Y) u7 c2 ?5 w. d           foreach($data as $k=>$v) {  
* C5 O0 J! v  K3 g+ a0 }% W              switch (substr($v, 0, 2)) {  $ S' @, g6 x& L2 Y4 R+ F. T
                  case '+=':  
/ A& C" L$ P+ h6 a% V1 P                     $v = substr($v,2);  + Q" U; @, i  t# [5 t' O
                     if (is_numeric($v)) {  
( }3 x! ]# C0 [                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
) R6 [' T- z( W3 u  f                     } else {  
6 ~/ {) w, \6 J' Q: M# q( N                         continue;  8 \9 j1 A5 C) p2 b0 C& X# C" W! |
                     }  
: Y; H7 q% r9 c. m  k  h3 Z1 u9 @2 M                     break;  % Y6 u5 N+ K' C1 Q
                  case '-=':  
9 y: L$ I6 a, }                     $v = substr($v,2);  ' v! m- L: ~8 [7 I. z1 V0 n
                     if (is_numeric($v)) {  : L6 }* ~8 L6 p
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
- f$ F% c, C# f% j6 E. Z                     } else {  1 t+ p3 K, p6 j: [
                         continue;  + P: k8 K$ `: c  S* _$ L+ S) I
                     }  
; O+ u+ P9 y* r/ j4 a                     break;  
4 Q. F4 U: g, M4 V                  default:  
, j$ C0 x7 p! H; f                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  3 y$ ^, F: |9 \  B( e6 D
              }  
# Q* K2 [- C/ v! F3 f           }  & v( Z" E; H" g- ^+ p) J
           $field = implode(',', $fields);  
$ v. R! C6 l6 b       } else {  1 X# N+ i; e7 N. r
           return false;  # o; m! l4 v* }4 Q# e
       }  " w: q) C9 S1 J1 U8 N# M8 U. [; V, g' e
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
) C. ~7 g+ s5 J: d       print_r($sql);  
3 l- `+ K" H4 @' d( ~       return $this->execute($sql);  2 G5 p' O' a+ m) I  M6 T- V, B, C
    } ' X" @0 V, G! `4 o. F0 j" n
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。! y, k9 X0 s9 l% x

" R; \  k; e/ V4 E6 x* e攻击测试:
) n  o# o7 L; |$ e测试地址http://localhost3 i) N) c0 m1 o; N
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
' R* z- N- ]: k# a, y. x5 r/ f  z" _$ E
! Y2 v; o  y1 J& w
% y6 a! s1 o; k* k2 {6 P
) `" T6 o' ^8 K0 k
9 O) c% Y; e( r- j  r
4 u8 ]: W, z9 w; h6 u9 U

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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