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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告! _0 g0 K( n; D" [0 `6 W/ D
漏洞作者:skysheep
1 `2 l4 e3 N& h% e2 _分析作者:Seay3 c0 |! D9 a% g
博客:http://www.cnseay.com/
3 u% v/ W9 m6 r: w漏洞分析:$ |7 O+ j6 u- K& \7 }
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
1 R& ?: E, }" c0 O$ e6 E0 X8 Z3 D! P# O: a# x+ I5 I) U

9 P: Z; n& w  V" ]; P: N' c2 n
8 @) W1 v5 s" s* |' Wpublic function account_manage_info() {  
- l& u2 L' q7 v* k) x2 H# Z" x       if(isset($_POST['dosubmit'])) {  
: m$ q1 ?  @4 U/ ~" J! y0 ~           //更新用户昵称  
8 M1 Q% @$ W, S4 O5 v) ~# v( V           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  , x2 y& \: }- @$ _8 ]- n
           if($nickname) {  
: W; i- ]+ ]" s9 g9 w              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  # ^1 ?- r0 D! }. P7 x+ e0 p
              if(!isset($cookietime)) {  
" q  I2 D  v. E' j; Y& G9 h                  $get_cookietime = param::get_cookie('cookietime');  0 W4 p* J" i; G: K0 y" L2 g
              }  7 `) L" T" ~& _% h9 D  o
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  & a9 l# F8 G# u. r
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  7 t) s6 L1 B7 L" y% J' a
              param::set_cookie('_nickname', $nickname, $cookietime);  
- ~: O$ v. T: {/ F% E0 b1 I7 A  j+ u           }  
4 }0 S# m0 ~2 z0 }, O* ^- u7 _           require_once CACHE_MODEL_PATH.'member_input.class.php';  
; f3 H1 s+ ~  |3 V; d' t9 c           require_once CACHE_MODEL_PATH.'member_update.class.php';  / Q( f6 V# Z1 V1 {$ ^' k5 W" w
           $member_input = new member_input($this->memberinfo['modelid']);  
0 d6 S% \( U# H: j           $modelinfo = $member_input->get($_POST['info']);  , U8 t3 ?/ R* p% C0 V/ G6 c
           $this->db->set_model($this->memberinfo['modelid']);  
6 I5 \& W7 ^0 j+ {5 b  o           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
" C& B( k! n2 d7 x6 H4 J% p           if(!empty($membermodelinfo)) {  ) i* g- s! F1 U, p: z0 |
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
$ Z- ?# O7 v2 U: J) y           } else {  
2 L* }! }) W1 x              $modelinfo['userid'] = $this->memberinfo['userid'];    V% ~; t; ?: {
              $this->db->insert($modelinfo);  
7 w- @! G" n! C! F. D           }
8 \' O6 t( A/ k代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
# J. i" A% \1 ?& H0 k* m" i在\caches\caches_model\caches_data\ member_input.class.php 文件中:
8 _' \) h' [  K  o6 B4 o- i) k6 q5 l: @/ ?& J9 A/ u1 m
4 P) r9 A( e0 [
% e; W- n: y" v: @0 a
function get($data) {  ' V0 j0 K8 @/ q7 S% g7 [9 ~& w8 V
       $this->data = $data = trim_script($data);  ; Z! G  _: [+ _, ^" g2 v: K
       $model_cache = getcache('member_model', 'commons');  
; G+ w6 x+ F+ w0 s6 ^       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  % ~; U: t  Q: E  J: w
       $info = array();  5 |+ w/ d. ?+ k# `
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
9 w. e! M) A- i3 A. F       if(is_array($data)) {  
' _% w* [9 B4 _5 o: z  a3 J& f           foreach($data as $field=>$value) {  9 F4 u' C& S) ~
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
* V' K; b, K+ \" ^& N1 Y* ^              $name = $this->fields[$field]['name'];  8 c  a) k$ V. E% s  O$ |# T
              $minlength = $this->fields[$field]['minlength'];  
/ {' |/ Q9 v5 h' W5 d              $maxlength = $this->fields[$field]['maxlength'];  % k; S5 x& q0 T$ [# N/ d
              $pattern = $this->fields[$field]['pattern'];  
) j; {1 P4 G1 n2 k6 E+ P0 ^' g/ m$ H              $errortips = $this->fields[$field]['errortips'];  ) t5 p, I  f" N, h0 h
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
6 L/ U9 w8 ^' S+ d3 h: W              $length = empty($value) ? 0 : strlen($value);  
  t8 q# Z- Y- F' J: g$ m              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  * u4 u) P( b9 O( B  r9 H) h, V
              if($maxlength && $length > $maxlength && !$isimport) {  
& E- A% ]( D# P0 M                  showmessage("$name 不得超过 $maxlength 个字符!");  9 C* |2 }8 J8 g7 z8 O8 p% G- l* ^( H/ C
              } else {  
2 M3 K$ F1 v2 K                  str_cut($value, $maxlength);  9 F/ x5 Y4 o# V, m
              }  7 ~* L+ x' Z4 `, x: N2 D+ I
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
6 {: b% b# `4 ]0 Z                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  . x3 n; l: x, z# \8 Q$ i
              $func = $this->fields[$field]['formtype'];  
: ^% O, t& I, q) p/ `              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
( N: L  {0 y& Z: w              $info[$field] = $value;  0 u" Z1 N/ A8 Z) y. A
           }  & N: s- O6 h; l$ U' R% C1 m: }
       }  # y7 q$ h$ b. m
       return $info;  
# _" i2 s' c  \- K    }
% ]8 i& Z: q+ `9 L) L+ k  ?$ Itrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
/ _8 Z0 ~% P2 x9 q! f0 B% v4 i% Z" K& P
再到phpcms\modules\member\index.php 文件account_manage_info函数1 r+ g- b. {+ \
过了get()函数之后。
5 f2 B' x: r8 z( s3 E+ a% [$ Z4 r* x2 A9 w& ~* ^* K5 @1 L7 D$ J# F

. _: x; v8 i) B' q, d# g% l; A$modelinfo = $member_input->get($_POST['info']);  
* [5 t3 c. r. `% k* R& k           $this->db->set_model($this->memberinfo['modelid']);  
7 Z; U, r, v, L* S# }  M& j. Q$ H0 C3 Z           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  : L0 a+ g7 d% ~, a2 R! b
           if(!empty($membermodelinfo)) {  ! M) P2 L$ @! _0 ]6 n4 H' _, p
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
. x1 a; ]8 k% Z; |6 G7 z2 f9 C           } else {
. u9 P! a- x/ `1 z9 I( y6 V直接带入数据库,update函数我们跟进看看
9 B; ~2 x/ i& u* e, x8 k: H4 A- C# H) D

% g) H0 _% I& n: rpublic function update($data, $table, $where = '') {  ' F+ S1 o0 }# O' [" p$ K' w) y
       if($table == '' or $where == '') {  
& d; w. P2 q- s; F           return false;  
3 C) |9 s  D: {7 a" W/ Y! }       }  & O- S& v  ~) Z' _
       $where = ' WHERE '.$where;  
: b8 U0 N+ L: {% e       $field = '';  
) p0 ^% E& j$ I  w1 p  B       if(is_string($data) && $data != '') {  
8 C! {! a+ `% U( A$ i6 K% W           $field = $data;  
0 ?: _3 \1 [1 ]. @       } elseif (is_array($data) && count($data) > 0) {  % K2 |" k+ t5 U. t" z. P
           $fields = array();  
% `1 H; X" b3 n           foreach($data as $k=>$v) {  
" g) G3 g1 O  D              switch (substr($v, 0, 2)) {  
% [5 v7 n$ {& n" Z5 Y                  case '+=':  2 F7 ]' B: m9 O6 ?4 ^7 c% l
                     $v = substr($v,2);  - f( L$ J( m/ i) `
                     if (is_numeric($v)) {  # i8 A$ {- n. W# q4 I
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
1 U3 ?% ?5 n0 S9 r9 U* q, ]                     } else {  ) `! w6 ^1 [$ v1 r
                         continue;  
- i3 T  d# d: L# ?3 d; u                     }  
* v: s2 a( L& Q/ {( M                     break;  ( b- u+ A5 H2 k" P: o
                  case '-=':  
7 X  @  W! f3 F0 m# i/ D  Y9 F                     $v = substr($v,2);  
9 A! t5 o, f3 p4 T                     if (is_numeric($v)) {  + U% x0 s( M: L* i5 J' k9 I: d$ x/ W4 o
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  9 i6 Z6 \1 {, n) Y0 w
                     } else {  
8 ?. N3 J% Q" q                         continue;  & ~( j! d* z5 N5 h4 [7 u
                     }  , ?' X* L4 T7 I4 [
                     break;  
% n  d' g% Q) v* T0 \                  default:  
) E5 f% s& ]; P& s9 Z3 M( a7 t                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  2 j. K+ F- D0 _7 l9 y
              }  
* ?" ^9 e& [2 m  p           }  
2 i* S1 H" ^+ h% n; K6 M  D           $field = implode(',', $fields);  
7 b" D# ^( x1 W( j) u$ P; A       } else {  , t3 F# ~6 T# N5 ~4 Q4 J6 Z
           return false;  
" U; i: n4 z- U! A; M  [; d       }  + z0 W& V6 H8 _/ ^% v
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  ( m& ^' `, ~; B$ L! y
       print_r($sql);  
5 d. O7 P2 [8 t4 Q' n9 O8 Z       return $this->execute($sql);  ' ^& o2 P6 _- d
    }
) j# d4 x9 Z4 D4 d5 [从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。; b$ n+ B. v/ V+ O& y7 |, ], L+ v! O& F5 i1 j
0 t, N" Z+ X/ m& e- O
攻击测试:& q, H2 O6 y$ H( u+ u# b7 @7 R
测试地址http://localhost7 }+ j) b( |+ t5 K
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
; m1 \, v; _1 v9 u. v: b0 x- Q0 I+ _4 d- x  W" ]

/ N" n! k0 ~6 c% }5 y+ ~( b; w# j6 w& ?' y, L/ M9 H
: i% C7 R3 Q1 h

) `2 t( ~3 Y! t; u

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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