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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
* D% d4 ~; W4 k5 {, Z漏洞作者:skysheep
6 @/ y1 v' B$ ~  i. M分析作者:Seay" q( E  b; w  \8 |
博客:http://www.cnseay.com/" _6 F4 x2 T! {3 N- k1 x
漏洞分析:' M- O9 ~. D' F/ S; k
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。4 G/ z" b8 C+ M* B: a; K

& I. p! P3 I& Z/ B, u' C9 j+ @2 ^5 k( y+ q6 _6 U$ v

$ @% J0 o8 Q$ {" M+ n- Tpublic function account_manage_info() {  
: S& b7 W$ s8 m3 n' z- \  }9 m; k       if(isset($_POST['dosubmit'])) {  1 |3 O5 j( C) f0 j
           //更新用户昵称  ' E# k4 E6 {/ G0 c; i* ]
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  2 p. e5 N' s1 C! O6 `, r# J1 q7 u
           if($nickname) {  
; O0 z4 A( g# c$ q5 ^! r3 D              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
4 j; o3 u: i2 d! y              if(!isset($cookietime)) {  
4 z% k, l8 a4 D% `8 e% K" J                  $get_cookietime = param::get_cookie('cookietime');  
$ ?0 O; H# a+ I; a. p. m              }  
% s2 M- `6 O; c* E$ f              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
! H* C# [: S6 k8 h0 h              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
) L0 {* \! ]9 T( Q& ]0 W$ h              param::set_cookie('_nickname', $nickname, $cookietime);  0 p  R- f" v& ~0 `0 h1 I2 \- P
           }  
; a/ g5 i' _: s           require_once CACHE_MODEL_PATH.'member_input.class.php';  
. l9 C; r1 e1 S0 k( u           require_once CACHE_MODEL_PATH.'member_update.class.php';  / e# t3 u  T6 [- ?/ `
           $member_input = new member_input($this->memberinfo['modelid']);  3 a: k. Z% B' g; E7 \0 v
           $modelinfo = $member_input->get($_POST['info']);  
" @, j, U' ]. O) E6 }  G           $this->db->set_model($this->memberinfo['modelid']);  # s! {. K  F  I+ N4 E
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
; }3 z3 v1 L+ W; M& F5 z           if(!empty($membermodelinfo)) {  
: K+ O; @. t* \" Y# ~              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  # m7 v2 A- U+ F% W7 C4 X
           } else {  
* H% a$ I0 ]+ V3 S, w: e+ y              $modelinfo['userid'] = $this->memberinfo['userid'];  6 l' B9 A0 {% {  ~; v/ C: c5 H- c
              $this->db->insert($modelinfo);  / }9 r! k$ ^% [6 Z, O* ]
           }
! \9 c+ v. C0 P6 ?代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
7 S% T# d" P( Z在\caches\caches_model\caches_data\ member_input.class.php 文件中:% H  K. N# J5 W. m

- |4 l# ]: N1 F+ o9 G! g! `/ c1 a7 A7 L5 G! {) N" B. Z4 w2 A- V/ X, |
2 i' @: o9 `2 j$ {
function get($data) {  . M7 i; C, L1 L
       $this->data = $data = trim_script($data);  
7 [1 K0 @# z+ C% n5 s( I       $model_cache = getcache('member_model', 'commons');  ' n7 k  G7 C" w9 J
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
. g+ {! |  M- n       $info = array();  
5 U1 R. v( [9 }+ F/ C) t6 T# u       $debar_filed = array('catid','title','style','thumb','status','islink','description');  * r* r: z# H+ k* N% z
       if(is_array($data)) {  ! h0 g0 U7 ?# g7 ~
           foreach($data as $field=>$value) {  
# N! b" `4 [9 I! D: K0 ^# d" R              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;    J3 b9 u2 ~* J7 F
              $name = $this->fields[$field]['name'];  ) U! E$ e' X3 T0 d1 z! x6 G; J4 G
              $minlength = $this->fields[$field]['minlength'];  
2 @. g8 h% N$ U6 l% o" W              $maxlength = $this->fields[$field]['maxlength'];  ! Q$ g% q" H) V+ p% [# t
              $pattern = $this->fields[$field]['pattern'];  6 n/ f; ^* s; R) R
              $errortips = $this->fields[$field]['errortips'];  : u+ d# }. y" r  e4 q
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
- G/ b$ q+ Y7 p. x( l6 s/ X              $length = empty($value) ? 0 : strlen($value);    B( R7 d' m/ x: C6 k. X
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  + A4 s" P* g$ y+ {, F+ k
              if($maxlength && $length > $maxlength && !$isimport) {  
3 S9 O+ S8 a! i( _+ L/ M                  showmessage("$name 不得超过 $maxlength 个字符!");  ! @1 \( s* _) m" n
              } else {  
. r! v8 I+ `/ i1 h9 V                  str_cut($value, $maxlength);  5 f% G8 W2 ]# K$ n5 ^9 c0 A
              }  
. r$ ?8 d! u- n+ B              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
$ ]7 x% `/ }) w9 ]4 w6 S                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
3 v# X3 U0 O+ s0 g  |7 G              $func = $this->fields[$field]['formtype'];  : f# s7 X& ?$ n+ X" L
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
/ E! }5 {5 i8 j$ u% i: p& c              $info[$field] = $value;  
; I: q8 I1 t! ?5 S           }  
0 I: G: ~7 F( t+ H, y; x! D& C       }  3 D) y' i; ?* E+ b. p6 G( e" M$ |
       return $info;  , @& K/ `. y% W4 m1 \
    } / |4 V7 B( Q7 ?3 z% [' j, `6 h
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,5 _& J, I: w( G3 h- N

/ G- N4 i/ ~" t6 F再到phpcms\modules\member\index.php 文件account_manage_info函数
1 @( G/ S8 x; {3 i过了get()函数之后。
- G, c  P4 \- V; w) J5 A
7 N3 ]7 c4 Z5 `( k7 E 6 D% e) x( |2 H2 M% ]% `
$modelinfo = $member_input->get($_POST['info']);  
- T, G$ l/ ]/ @: w: t7 s           $this->db->set_model($this->memberinfo['modelid']);  0 F  z5 H5 h8 p8 |) F: b% L( a
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
% _; T8 S6 s0 T+ V           if(!empty($membermodelinfo)) {    N0 |4 H" H9 p- V( X0 ^
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  0 [' \3 l. B$ o! R1 R
           } else { , K( L( n( f: q* X  e4 D8 f8 T* ]
直接带入数据库,update函数我们跟进看看% p. m' _/ [1 u1 t. E; p
​
* ]# S& f* g9 Z$ l' G8 h2 I 9 [: i* t" _7 ~1 f9 v
public function update($data, $table, $where = '') {  4 v! m9 ^* E3 B6 x, d
       if($table == '' or $where == '') {  - H) h0 J3 O3 I5 d. P
           return false;  
, ]& D/ D$ p/ d0 Q       }  9 r- ]6 l! k- B. a
       $where = ' WHERE '.$where;  6 M1 {5 C) ]& P' t5 W
       $field = '';  , b. Y4 k" w. ~" V
       if(is_string($data) && $data != '') {  
( S" C9 H8 `8 s, i6 C9 g5 T9 Q: m* |           $field = $data;  " ]% q% M( R; n
       } elseif (is_array($data) && count($data) > 0) {  : ]9 U! G- k# D; U3 R: W
           $fields = array();  % J7 o' x( N0 L
           foreach($data as $k=>$v) {  
4 E2 u6 s0 X% G" p* l              switch (substr($v, 0, 2)) {  
" r: y7 D9 n5 C( }5 B) Q' \                  case '+=':  
: ^9 J; [  b' U  I/ c                     $v = substr($v,2);  7 V9 E( R6 G- B" Y
                     if (is_numeric($v)) {  
, I" l) Q$ c; K* L4 e6 X                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
' ^! h* ]) n- ~                     } else {  $ r; [5 q+ g5 o. l
                         continue;  
5 Z1 b4 }# u, B                     }  
! B/ _1 \" N' w3 [; v                     break;  
0 P$ D# a% T. x% T                  case '-=':  * Z6 O8 \3 K8 S
                     $v = substr($v,2);  
# m* ^% s8 w+ M3 I( G- G- L                     if (is_numeric($v)) {  
2 y# b" X& B! F1 ?1 f" M2 E                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  6 Q% q+ Z. ~7 |! M
                     } else {  . g+ ?# Q% R# g3 U# @5 I- e6 E
                         continue;  
% X+ I/ i( V+ l                     }  
( K% X0 \( d  X/ @7 A9 h                     break;  
, n8 |) f& f! j8 @: M- ~9 W                  default:  
& j& A; z: z! Q. u                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
8 W3 \- j; m4 D4 E) ~2 g" c              }  
8 {  B. s% I" j  Z+ Q) X6 }: K0 J3 d           }  
7 p. Z1 n8 F& |: n4 P           $field = implode(',', $fields);  
% \- [- P" c) R. O       } else {  * b5 U$ I' T1 c8 q4 _0 h! W
           return false;  5 V% Y. P! Y$ f! M! m% j( k
       }  * Q# z7 o: ]- y) H) ^5 N2 }
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
# G+ a7 H+ W  W6 w( v9 L0 \3 x$ J       print_r($sql);  
# ?4 ?1 D6 [! F$ w( ^0 ~       return $this->execute($sql);  
* c" }8 M' F- b    } / Q2 R7 y7 {' h) Y. \
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。. Y6 j2 ^, \0 m+ M& v! u. F- m8 J
) p2 P* ^! P! M8 ?1 m, w" Y0 G: j
攻击测试:1 C, A! S# m" r$ y% l
测试地址http://localhost
: j, ?9 y! N: C  ]3 x4 N, L* X" U  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句1 B$ j' U: a% R; j! ?% U4 ^

! m9 g, o/ A! n& A
$ @$ N% j  j' E4 ]1 x3 D
( Y, f) ?- W7 S: A6 P5 ^' i! Z6 h, E% u) y- E
9 y8 p* {2 `  R8 P+ f

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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