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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
# ~! p5 a  ]# |. h+ F4 `( J* n漏洞作者:skysheep
! `  K6 a6 t2 s* `8 Z. n分析作者:Seay( `. J% d/ u+ K/ G
博客:http://www.cnseay.com/6 `8 x+ R1 t1 Q. e) M* G: s
漏洞分析:, A, r" z) {0 C4 C
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
3 E" k0 U9 p$ ^7 I* O5 J* X
; U" p6 s. I1 R" I& t  R+ n" ?! i( j0 M3 F* o
. v$ W% y: \; l8 U
public function account_manage_info() {  ) V/ {" C8 a$ M7 y9 |2 e+ L) S
       if(isset($_POST['dosubmit'])) {  ; s2 b: R  r; x! z' {% ~
           //更新用户昵称  / H. O& P) x, @
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  . z6 H7 R* h6 o8 v
           if($nickname) {  
: _, J: y+ k: {6 V; Y              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  6 z' ~0 M# j4 v; U( L2 R+ N
              if(!isset($cookietime)) {  
3 b+ `- l3 F& }( }" Z& z. M9 W  d                  $get_cookietime = param::get_cookie('cookietime');  & J0 [/ L0 o( m* F: O1 n4 [% L
              }  % r: P; K1 J- _  P, t1 n
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  " f2 q& E+ Z" [: k
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
$ t$ _. D3 P7 q              param::set_cookie('_nickname', $nickname, $cookietime);  
! c0 T. P9 o$ h, {6 |, T           }  
) F5 \. M/ P! N           require_once CACHE_MODEL_PATH.'member_input.class.php';  
7 s+ V) q: s* ?( Z& P* r           require_once CACHE_MODEL_PATH.'member_update.class.php';  
( Z1 F6 L7 \, ]& W  Y  A5 [" z           $member_input = new member_input($this->memberinfo['modelid']);  
5 S, p# F  Q+ i9 M/ d4 W8 T9 u           $modelinfo = $member_input->get($_POST['info']);  
1 J# c% r/ {( w           $this->db->set_model($this->memberinfo['modelid']);  7 @0 q1 k/ v6 y6 Y9 h
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
, N4 _) `. t1 }- O: |7 M$ {! ?           if(!empty($membermodelinfo)) {  3 C& l2 B3 Y4 f% I& B
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
6 _6 ~: O4 }# z( M3 B           } else {  # Y( e8 D  }, A4 L0 J
              $modelinfo['userid'] = $this->memberinfo['userid'];  
6 D" z8 g5 F7 h' t              $this->db->insert($modelinfo);  
* {. m2 v( ]6 D# S6 p; F( X           } & |0 N9 Y: C; j$ X" O) B
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
; @1 S- \9 d, a( W在\caches\caches_model\caches_data\ member_input.class.php 文件中:
, D7 s3 m% G7 s/ x
8 l, C$ D, E4 ?7 ~3 t  f. J$ M& w( |1 D7 Z- Q

: j. c& v/ D0 X, z) jfunction get($data) {  ' ^# ]. J: [/ Q: \! j
       $this->data = $data = trim_script($data);  
' r: _2 x6 f0 S  e+ X/ Y1 U       $model_cache = getcache('member_model', 'commons');  
- _; e- K* v7 n+ b% ^/ m( @5 P$ o! e       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
8 m+ A0 R2 I9 A2 p+ j5 K       $info = array();  # V7 H' f9 M  b5 z1 [5 q
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
3 u- j) s- x. P0 X9 I% Y       if(is_array($data)) {  
$ q+ B: T4 B: N3 Z4 B           foreach($data as $field=>$value) {  * H$ [. {0 X1 z
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
. _% Y8 w( X) Y( r              $name = $this->fields[$field]['name'];  % Y6 @/ e0 K& O8 ^; s3 Y! `
              $minlength = $this->fields[$field]['minlength'];  
" ~" A: e$ ~- k              $maxlength = $this->fields[$field]['maxlength'];  ! I" Q; C) W( B: L; e( R1 v$ ]
              $pattern = $this->fields[$field]['pattern'];  # _" f" [7 ]4 P. s/ u6 q: a% a
              $errortips = $this->fields[$field]['errortips'];  & P( g. Q# k$ I7 W
              if(empty($errortips)) $errortips = "$name 不符合要求!";  / z" p, Z# [, J' \# l
              $length = empty($value) ? 0 : strlen($value);  
7 K4 }- q6 I3 z# z% [4 @! q              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  4 l6 J, a" c0 X3 M1 [% X
              if($maxlength && $length > $maxlength && !$isimport) {  + c3 G# v$ Y8 t  k6 i6 \$ ?/ D
                  showmessage("$name 不得超过 $maxlength 个字符!");  $ u/ C& W% {# J# g
              } else {  4 B# E8 P. P4 o$ X
                  str_cut($value, $maxlength);  ! f' Y8 j9 C! _
              }  
/ i8 G2 G( Z  h6 E* b( o              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! z1 g  _+ G8 p$ @* Y% l
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  0 j% p# V! f! U4 Z7 F
              $func = $this->fields[$field]['formtype'];  + i% U3 ]$ r1 T- y4 S6 H
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
4 I7 K. d" U. i% {2 k4 L              $info[$field] = $value;  & Z% t$ q9 y, D% _
           }  , }) h" ^1 p* v4 _. k, ?' y
       }  2 u' E* A1 p0 n9 c
       return $info;  
* H2 i/ K2 Z$ K    } % Q6 Y% b0 [0 {) O" Z5 D
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
: q! j% B; r3 M2 k5 ~" p& M5 Z/ ]; x7 W' E
再到phpcms\modules\member\index.php 文件account_manage_info函数
! c; H! H  g4 c/ [  B6 y1 Q过了get()函数之后。* G4 C/ x' r+ h2 T

4 V, d/ Z& W* B$ M; s) h1 H9 u 0 _$ l1 l3 d% B% ~4 W
$modelinfo = $member_input->get($_POST['info']);  . l) I5 b% f  s' b& c
           $this->db->set_model($this->memberinfo['modelid']);  
& }0 m7 p# g% l& O, |2 S. n           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  # e' I% `5 d2 j2 e- I
           if(!empty($membermodelinfo)) {  
3 y, ^( C5 q1 u& \& R              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  6 ?( K6 Q0 n& t+ D4 V
           } else {
: X5 {5 _% k4 n5 ~直接带入数据库,update函数我们跟进看看7 ]& R/ q4 E7 j5 m

7 P+ x1 u! J. L' r8 [! H9 R
; b" F* W/ g5 u: a3 `' ^public function update($data, $table, $where = '') {  
4 U* W1 E9 h- n7 u) N4 H       if($table == '' or $where == '') {  
2 y& K2 B5 [* N# ~6 D           return false;  
5 X0 y7 l0 C1 S2 m5 b, K       }  ( i0 I" b* H& k6 I0 g) A
       $where = ' WHERE '.$where;  
, V9 z4 n- ]3 f. A8 ]) J* |       $field = '';  
7 t. p& r( r1 m  u9 Y5 n, s# j       if(is_string($data) && $data != '') {  
) j! g3 ?- e  `           $field = $data;  
/ s3 T+ O9 ~( G6 i8 |! a1 N& F       } elseif (is_array($data) && count($data) > 0) {  
- ?' Z3 q& F/ w, }1 r           $fields = array();  0 \+ d# D" u& A2 H  }# A9 m$ ]& y
           foreach($data as $k=>$v) {  2 R; F: H6 m: h4 N1 h2 p' v/ l) o
              switch (substr($v, 0, 2)) {  8 c& ~4 |  X: E5 U' H
                  case '+=':  3 s' \4 {* H2 X0 L# @; ^" j; j- N
                     $v = substr($v,2);  
" K* r  Q: j% F8 v) b                     if (is_numeric($v)) {  . M0 X8 O) O& }& G+ }4 Z. Y$ q" _
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
8 D; M6 {# \( f' h                     } else {  
# e0 p& O, x- V1 P0 u6 h                         continue;  
9 e; R& U' |) m" N& M7 [# n) e" S                     }  ) c5 r6 Y9 K' ^: F
                     break;  ( Z' r! Q" H$ [9 x2 E$ @; w
                  case '-=':  # {7 p" y- G  B2 r1 b* A
                     $v = substr($v,2);  
) W5 E, U0 c8 ?! c: ~                     if (is_numeric($v)) {  
& U/ v& c% `# q# |                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
5 A/ Y, Y  u* t4 d& x7 @+ H                     } else {  " r# i: ]- D7 F- A9 q! ~
                         continue;  
# `/ S/ x3 z) z- b- u6 g9 J( F* l                     }  
# d3 g6 Z6 L6 G- O                     break;  ( k+ A; s" z6 k' P( U! U$ F5 ?
                  default:  " b# s5 ~+ v* {
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  $ a* D% t/ T4 W4 P7 m
              }  
7 _2 P$ a$ S$ q' `9 x5 `) l, ?8 i, \: n           }  % I' d$ ], I  p- G# {, }
           $field = implode(',', $fields);  
9 S" {# K1 Y( j* I3 S* j       } else {  
+ `! Z4 k6 z! g, ~1 Q           return false;  
' r' L* ~- v5 ?9 H0 H1 |       }  $ D$ F4 y2 P6 L& {
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
3 {: \# I# H* _       print_r($sql);  
& T0 H7 Y( j1 X       return $this->execute($sql);  $ s8 o1 K) P) P3 Q
    }
" I- D# W$ G& r8 y9 J, b从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。: L  ~% `' {$ w4 \

0 L2 v* H& o+ O2 t: @攻击测试:
. b& }9 d! y3 h测试地址http://localhost/ V* ]9 n9 }9 E) s$ W+ h6 [8 O
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句* n) K& p$ _- R& Y( \! d( T
. D: `8 ]  s4 T$ l& B% F' F- s! X

# h$ q. n+ i! O# S1 N" l$ ^
( N! R) ^- C! z7 M9 p
) M. b! R) G+ C$ `7 z! z) @- E/ p. C  b' ?1 {- f6 k

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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