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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告) X; \- x$ y$ L
漏洞作者:skysheep
1 \2 e: H2 G" e8 E/ I) d分析作者:Seay" N! k" @, f( X
博客:http://www.cnseay.com/
) s; R$ [# n5 q4 f' e6 v漏洞分析:( y5 [; u  k* Y) S+ f8 W& H( Z# K
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。: m# L" w% `0 C2 O9 K# A' E2 u
. K4 p) C" |( r! M/ n8 E
) E$ Y2 I: Z! U% w8 i( x- b) q
9 Z! b) S  P7 `( @  e3 {- n4 w
public function account_manage_info() {  
, R/ a' {- @6 G* k% `) |% C       if(isset($_POST['dosubmit'])) {  
9 h8 V& g$ R6 M! J* ^' v, _9 q% M           //更新用户昵称  / J0 Z& _& M8 T# A! s
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  $ l" O' z+ t" G% ~/ L" a+ N
           if($nickname) {  
% }8 o% ?9 t; t% Q- L3 Z2 Z) v% s              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  , b6 k( Y7 o- a0 n- O. N
              if(!isset($cookietime)) {  
% N' a4 s# q( L( E8 Y6 u0 t! Y                  $get_cookietime = param::get_cookie('cookietime');  
! C8 }! @! q) R2 h* B5 \3 F              }  & \/ j  Z3 \4 N
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
4 x, ^5 J. O4 M7 x              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  6 P  A/ Y3 B- J3 u, z' q
              param::set_cookie('_nickname', $nickname, $cookietime);  6 T* l1 o5 S6 o2 D5 z2 M# M! _
           }  9 `3 J4 Z" k! `; [8 ^
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
% Y9 T, e! L3 O9 n( b4 t           require_once CACHE_MODEL_PATH.'member_update.class.php';  + c' _# U" T4 Z# g( x, D
           $member_input = new member_input($this->memberinfo['modelid']);  . \) g3 t. {2 L7 ^0 m) C/ {2 O
           $modelinfo = $member_input->get($_POST['info']);  
0 z5 I6 q0 M, _- w" {           $this->db->set_model($this->memberinfo['modelid']);  
4 O3 G; p6 K3 {           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
( Y! g- H/ x) C' s% ~" m  d9 G- z           if(!empty($membermodelinfo)) {  0 s% c/ K4 s- b# x( c
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ! R3 H+ P. p* {* d1 }
           } else {  
, b$ k4 c% _" H: d5 W9 b              $modelinfo['userid'] = $this->memberinfo['userid'];    D: G8 c1 |: d) H
              $this->db->insert($modelinfo);  
8 y2 J. U. {$ ~           }
; e& \2 _3 O. f; i* T代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
/ o) R0 C7 [% D) c在\caches\caches_model\caches_data\ member_input.class.php 文件中:
# T, [- h8 J) ~9 w7 @' ?6 B  Y) H! k" a, L

3 ^5 M! D% i' P$ h7 w
8 d# W# K( Q1 _2 `% z. q" e' i+ yfunction get($data) {  
$ j/ d' ?& T' n& t7 r0 }9 ]1 N       $this->data = $data = trim_script($data);  
7 ?4 _& L% B5 E% h/ p( m( s       $model_cache = getcache('member_model', 'commons');  
8 c* F3 J3 `) \7 ], W1 r! Q% e       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
5 }5 ?6 \. g2 k, W0 d0 L' @       $info = array();  
! _6 B' M! W1 _) n% _6 K6 M       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
4 ^& Q4 K5 S& v8 C, ]       if(is_array($data)) {  
' @, x6 E$ J# J3 S" X6 C           foreach($data as $field=>$value) {  
8 }5 b& G8 o  y1 T0 e7 ?. Y+ s+ O7 R              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  2 Z0 l- I* u9 g9 o. v) F- L
              $name = $this->fields[$field]['name'];  
9 q% Q6 y6 U- r" E/ A1 J+ |              $minlength = $this->fields[$field]['minlength'];  
5 r  j0 g  G$ A/ J: Z              $maxlength = $this->fields[$field]['maxlength'];  6 g0 j2 n2 R+ |/ R8 H' l
              $pattern = $this->fields[$field]['pattern'];  
6 D4 l; ~$ C/ Q, A6 W; E% |+ |' w( {              $errortips = $this->fields[$field]['errortips'];  8 j+ {6 \8 m: ~& O
              if(empty($errortips)) $errortips = "$name 不符合要求!";  + o5 n% H( |0 @  B1 g
              $length = empty($value) ? 0 : strlen($value);  
0 A) c/ a: B2 c+ C% M+ W* g5 y0 \, R              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
5 c% K2 Z) D3 C. s% l1 j2 L              if($maxlength && $length > $maxlength && !$isimport) {  # T; ?1 p+ B) o
                  showmessage("$name 不得超过 $maxlength 个字符!");  ; h/ C# b0 i" Y! f8 n
              } else {    }" q, S# P' [0 j  {) G/ A
                  str_cut($value, $maxlength);  
% F: f) @- U4 A, O+ r              }    f4 u* t! Q$ t7 u* Q! m% |$ L6 x
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ! w, G; x3 a% i- S3 [
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
/ O" l7 d( B& S              $func = $this->fields[$field]['formtype'];  & R: s% x2 ^3 N; L
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  3 I& o. v; R( `! m- [
              $info[$field] = $value;  7 d- w4 R( p2 Y) p: y
           }  # d7 H& Q& J/ @/ m4 @9 O! F
       }  8 K, F1 d' a* y' r1 K
       return $info;  
2 T+ ?2 a9 @7 f# B    } . {# _7 \+ {) W0 f  x
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
. r- M5 \  {9 u8 z
4 T$ Y( U- z8 {" x+ d2 Y再到phpcms\modules\member\index.php 文件account_manage_info函数
) s' V# N! E. K过了get()函数之后。0 g' N% t$ e% a; r$ N1 a# ^, j1 t4 t
# ?7 W9 K: h" W" D) t5 Z
/ b( f1 a. B" E4 k6 i
$modelinfo = $member_input->get($_POST['info']);  $ r0 t4 K+ S" O( D
           $this->db->set_model($this->memberinfo['modelid']);  
( J( J3 V/ b- ?           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
. V+ s6 E6 f* K- g$ v" j7 w           if(!empty($membermodelinfo)) {    W6 U9 A7 {1 s- Q$ Z  T, \) |4 u
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
2 g7 K# I1 G! I9 E: h# h           } else {
0 z2 c3 l4 W+ y1 P7 H5 X0 F直接带入数据库,update函数我们跟进看看
) G  L9 ?3 _3 ~- n7 c4 h& Y) v* p2 z# L: w

0 W7 b$ ^7 ^8 u' u1 k4 M1 _6 Spublic function update($data, $table, $where = '') {  
! V' F) M1 w+ S       if($table == '' or $where == '') {  ' y7 D, E2 Y3 o9 W
           return false;  
$ D) Y- i, L5 Y0 m: B       }  
2 _, t$ c+ ?& ?       $where = ' WHERE '.$where;  
  H" Y: U8 C1 K8 j# j       $field = '';  
) A* |- ^* e5 u8 t8 c       if(is_string($data) && $data != '') {  ' w+ A' D) E$ h( D6 J' I
           $field = $data;  ! }" J9 F( M0 _9 m% K5 `- K" U
       } elseif (is_array($data) && count($data) > 0) {  
4 ^, N0 \, U7 R; o' v           $fields = array();  
) l/ i6 m( @& ~* F           foreach($data as $k=>$v) {  
: _; K1 u6 G  l0 B              switch (substr($v, 0, 2)) {  1 A, @+ b' t, L
                  case '+=':  # p. q: Q# T/ V  j2 A7 l/ W
                     $v = substr($v,2);  
  \* N' k+ g# e% D0 l$ w4 f; J                     if (is_numeric($v)) {  
- {+ R0 S3 B# i7 s                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);    B6 q( z1 L4 B& m8 a5 \% ]2 P; ^
                     } else {  0 U+ \3 }; L( i
                         continue;  1 l$ _8 }4 T0 W
                     }  
! d( ]5 |1 V% h% s5 [3 G+ `$ S1 w                     break;  
6 i# [& g0 F4 L                  case '-=':  $ N! z" _: `8 E
                     $v = substr($v,2);  , y& y# B7 e1 t) p) m9 u. e
                     if (is_numeric($v)) {  
6 T( K- W! |( `                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  0 |, E7 v4 }! T# o# u  P
                     } else {  
$ i: B% [+ U  o- l                         continue;  
) a, n, M7 c* I7 x                     }  
* E: c; F. x5 B; X) S                     break;  2 A8 M! F- k, O+ H0 z. V1 ?
                  default:  
1 J( L: E  d9 i* K( i+ S6 F                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
9 J9 j8 ~/ b" i              }  $ @8 [5 n- x) }  J
           }  + I9 h/ Z* |- P& a5 ]9 j& i
           $field = implode(',', $fields);  
7 ]& R; s( g5 i1 X: t3 \* B: V       } else {  
5 y$ z: e) c5 @9 M* ]- w           return false;  ! R, Q- Z5 r5 ?6 d
       }  
+ M9 {3 L, |" |2 K9 S+ f       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  1 @7 y4 N& r% t
       print_r($sql);  ; ^+ z! ]2 [& w6 n7 Z) q
       return $this->execute($sql);  
. ?* a; {- [  d. `, A    }
9 n: n! r2 \' k; Q- Z从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。  N0 J" Q$ k: R6 r. M" b. z

* ], g8 P% U' x: j攻击测试:$ A- \! c- B2 y: P% L9 Z; w, [
测试地址http://localhost6 k+ C* N6 r% }$ E: ~$ N( v
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
' r: h. B' `3 F, J( t2 N" Q% t( ~! @# U# g8 t- E, \
; t3 ?( \# i/ f5 n( j* h
, v5 ^1 c" @) G8 l) d7 e
& a6 m  S& H- |/ X7 u. E2 K
! a4 G( `$ x' u0 V$ j/ u: H

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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