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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
, a  I- ]9 A8 t& A/ }漏洞作者:skysheep1 e& G) U! B8 g2 o$ n  u
分析作者:Seay+ {1 }6 R* B( I$ [
博客:http://www.cnseay.com/
8 l% w1 M0 P. B( [漏洞分析:
$ }! }: z; m* F" E  S8 m$ L  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
% `% \( J/ H3 k: L
" O# [0 a( g+ A  r) ^7 C, T2 G5 G$ h" w1 k6 `
" h0 }6 Q" I* f1 q
public function account_manage_info() {  0 _: `7 U7 _5 P/ j. z
       if(isset($_POST['dosubmit'])) {  
  t& a* y0 P% {5 z. s; j# Q           //更新用户昵称  : F+ |+ Q# R/ ^/ ~. D& u- b. c* h
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  8 W- g5 G$ V% E9 n* w
           if($nickname) {  / I( \( D0 g3 o( o
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ( S  ~- |* |, j/ g# V0 a3 G
              if(!isset($cookietime)) {  # k' B5 M! Q) G1 `2 W
                  $get_cookietime = param::get_cookie('cookietime');  & L5 g( g1 u' a* ^3 o
              }  
( |6 M1 J8 o4 g6 T              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  * E5 }- ?! v( C2 R
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  * b$ g8 ^7 Q# D+ O
              param::set_cookie('_nickname', $nickname, $cookietime);  
5 m$ S* F+ S! N0 M5 O% p( j           }  9 A5 s) y- w, T. X4 e
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
# m! g- A( o1 I9 k0 }: {. `% E4 m           require_once CACHE_MODEL_PATH.'member_update.class.php';  2 t% `  m: i+ t/ g" |- c
           $member_input = new member_input($this->memberinfo['modelid']);  
' l4 |9 y* L: l; I+ ]           $modelinfo = $member_input->get($_POST['info']);  
% n8 @' _$ d/ z" f2 z7 K: u, H- g           $this->db->set_model($this->memberinfo['modelid']);  
7 r5 i; B1 k4 t4 |  ^+ y           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
- c9 Q8 z3 r, Q           if(!empty($membermodelinfo)) {  
) G! E/ X6 m. g/ H% `/ b              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
* S1 I8 s) w8 I, D3 o7 j5 j           } else {  
, H* m* e- o! P1 r- J              $modelinfo['userid'] = $this->memberinfo['userid'];  
4 L% }& b6 n1 V# C7 A0 ~              $this->db->insert($modelinfo);  
- |, z0 b4 C, G9 I! W/ X: @# x           }
% {  Y* D5 ?6 M- u9 o  _代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,' v; ]8 h! s, I, a# I3 s0 E5 O
在\caches\caches_model\caches_data\ member_input.class.php 文件中:) m/ Q( G# Q) \2 W& _3 K1 j
9 y) t: V4 k) [4 q$ X& I

0 j0 p( \6 f$ n. R
! _- e% G9 F/ Qfunction get($data) {  * _" o% \# v; u/ t. D, X2 ]
       $this->data = $data = trim_script($data);  * {* m( I0 j3 k
       $model_cache = getcache('member_model', 'commons');  
$ |" Z# i1 L- Z# \$ `" ]       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
8 v& j' p2 a, I6 F. J7 N       $info = array();  
! v! O; l- S. X& s* S       $debar_filed = array('catid','title','style','thumb','status','islink','description');  8 l" G# r0 |, s3 L" t
       if(is_array($data)) {  6 i- j/ @% b7 j/ g" ~0 u4 e
           foreach($data as $field=>$value) {  
3 z0 T2 a9 R6 b# @/ f$ A              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
( |) {4 ~7 |* n, [4 ~' r0 q              $name = $this->fields[$field]['name'];  
2 Z4 S* b* S- ]: e+ @# a( {              $minlength = $this->fields[$field]['minlength'];  
# C% L* @$ p$ x$ N% o/ ?              $maxlength = $this->fields[$field]['maxlength'];  6 a" r0 _! J0 z4 w, P$ j
              $pattern = $this->fields[$field]['pattern'];  
8 F' p+ M$ S. I, X/ v, N' I2 T/ ^              $errortips = $this->fields[$field]['errortips'];  
+ o+ b& G. V7 I5 F) O              if(empty($errortips)) $errortips = "$name 不符合要求!";  2 U1 j5 {! p  e* h! e$ O4 ?. p
              $length = empty($value) ? 0 : strlen($value);  
; y& g8 t& {/ |! p/ B% E) a              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ; {6 |6 I7 M5 L# P
              if($maxlength && $length > $maxlength && !$isimport) {  5 s/ B0 Q; r# p
                  showmessage("$name 不得超过 $maxlength 个字符!");  
8 \" a: f5 D# A6 w+ L$ ~              } else {    n2 Q" h7 D+ R0 M
                  str_cut($value, $maxlength);  5 g8 U8 W( h7 l! ^, h
              }  ( ~2 N( _& M- O9 I
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
% y: G3 K& b$ _0 e, G8 }' [                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  6 d5 `( m- G! j; T3 M8 \! ^
              $func = $this->fields[$field]['formtype'];  6 Q' i" S% [. i$ C
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
8 S8 P, j  H, H! X+ B              $info[$field] = $value;  & e. m8 x! J  m* w5 N& S
           }  
: M/ ?( l/ ~2 }& {       }  
& J! F3 p0 T4 m       return $info;  
0 g# o- `# M1 \9 U    }
( o4 Z0 X8 Y* L5 `8 btrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,# B3 u1 F# x; U

6 _3 `" K, W) A& y6 k9 `% k9 p: q4 W- ~再到phpcms\modules\member\index.php 文件account_manage_info函数
  V3 ^% K& l: J+ |' @3 [. }过了get()函数之后。; X( ~2 g# Z  X. a
) P9 a3 U' {/ f! s5 L3 _" z
9 d. U! f; S# N2 ^% M
$modelinfo = $member_input->get($_POST['info']);  
! c  v- p1 k/ c           $this->db->set_model($this->memberinfo['modelid']);  4 J. X& D% P- z
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
1 a+ t& ^! @" r2 K/ ]8 x' @           if(!empty($membermodelinfo)) {  - V: P% l: P  J" M; }
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  1 D2 ]* N; A# I5 \5 a. `5 Y; }! l
           } else {
  v( P3 \; D3 T/ V+ c5 K直接带入数据库,update函数我们跟进看看5 d3 B8 K4 t/ `. g. N. }
4 {3 M' ^1 T5 R1 {
! s, s5 x5 e5 N  ^+ U
public function update($data, $table, $where = '') {  
4 S& w. ^* }% G$ k# N       if($table == '' or $where == '') {  9 E0 g' Y2 \( d. p! m  u
           return false;  6 \5 R$ {8 j5 w5 j. g- V
       }  
/ \, F6 f/ b. Z" D3 Z9 ]1 e! \       $where = ' WHERE '.$where;  % l, E- [" S  b; m: R
       $field = '';  
: c! l+ {- q& |& Q2 _( Y       if(is_string($data) && $data != '') {  
' b! t7 @9 I$ k+ f# B           $field = $data;  0 u$ F0 W2 Y1 P( l+ k4 D( W' A  s
       } elseif (is_array($data) && count($data) > 0) {  2 w* e0 {; J: B$ G1 Y# s) R1 p2 e
           $fields = array();  
0 M8 t* S7 k- t, Y9 j; w6 W           foreach($data as $k=>$v) {  
2 B& A1 e' d2 ~4 k, {              switch (substr($v, 0, 2)) {  
9 E6 L: A8 {+ @0 \: F  a                  case '+=':  
0 I! ?5 L7 N( K/ B" T                     $v = substr($v,2);  * ~8 E" S2 `5 F, c  g& ^
                     if (is_numeric($v)) {  
7 i: q  {, d5 L/ T4 N2 ?                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
2 u0 |' V: m' {( }7 U% I) o" o* U                     } else {  
( ]: e9 \9 M7 z9 Y6 y                         continue;  ; [4 f* ]" }' [. y
                     }  9 p! v9 N! F2 u# R8 m; I
                     break;  
3 t2 z9 U1 N& c  |) x* _                  case '-=':  
7 t: }" x2 ~* w2 W2 n  P5 l                     $v = substr($v,2);  
' u3 I( B& X$ t4 A1 u) s) u* t* B                     if (is_numeric($v)) {  
5 D: G2 q1 ~: Y2 o9 f" c                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
9 y0 w% ~+ O  M) _                     } else {  8 X/ |  c, Q# U  i2 \
                         continue;  ' L& c& N* {; a
                     }  - V% V0 J% W$ f
                     break;  
8 }0 k/ o! E* f                  default:  $ n: i  K: w* y4 D, Z: B5 e2 R$ x
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ; q/ f9 S! |% i
              }  
) L/ L" E! ]8 t+ d/ F1 ]           }  , G% N* U7 a5 L6 f; c
           $field = implode(',', $fields);  * J$ W) `4 D8 c
       } else {  ' O$ F7 R6 x) N
           return false;    z9 F& z8 k* Y; G* c* l2 T
       }  
* m; t) ?4 k* M5 w! L' V       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  3 P# ^: V# f$ U0 P4 o( H
       print_r($sql);  
9 G4 L2 ~& |# h7 k9 F. n& X0 M       return $this->execute($sql);  5 G# j, j0 h+ a% @8 |8 H4 ^
    } 5 b2 C+ r3 c! A+ M
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
) g* N0 Q8 M: A. V" p0 }# _3 ^* v1 \" b# z" y6 c9 D/ X0 Q7 o
攻击测试:
; r: Y3 a7 Y6 A1 W测试地址http://localhost  h( v; Q" D- M
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句3 N, ~# j. d; O4 E

) [+ q  J& U7 Y- x2 F
( o, k6 ^" N. f  |+ {% h: n$ T% {) z8 c5 y
5 x1 Q1 Z5 S% o6 G7 U4 ?
* d& }4 N) N7 w. }' R

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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