找回密码
 立即注册
查看: 2842|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
3 F2 ?( c8 c  S  N3 v9 Y7 M% ^% e, U6 Z, \漏洞作者:skysheep6 [7 w7 M6 s/ j; B. w+ F5 y
分析作者:Seay
8 o0 N4 ]9 y8 ?- t. u* r博客:http://www.cnseay.com/
9 c0 C2 _' i. T. p2 q漏洞分析:6 Q- n/ e  M( C/ |! U7 k
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。' o1 U) g8 s. q
1 O& }' d0 L0 j1 s7 r/ r
: z+ c" k" Z' P/ T# @, [9 w
/ F- q& D- k" L8 a% j  z) S
public function account_manage_info() {  
; D/ X9 h* k7 [% p4 O       if(isset($_POST['dosubmit'])) {  
1 {1 z3 f3 ^# W& n, ]# b           //更新用户昵称  
2 j- Q# U# ?+ m' O           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  ) K9 r$ @4 ^" X; I
           if($nickname) {  
0 H  z! K2 R$ f, ~- E+ e5 i$ E2 n              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  4 {7 T+ @; ?. {- f+ Z
              if(!isset($cookietime)) {  
$ C" }+ C2 U) T% j                  $get_cookietime = param::get_cookie('cookietime');  0 S" l5 r4 ]" \6 q/ f% A
              }  
  C& b  A. f  _8 R* B              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
2 R6 @1 C! {& B; k              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  2 y- j& ~6 m4 }$ _
              param::set_cookie('_nickname', $nickname, $cookietime);  , U# L, g' h. I+ [8 w; t& d) M
           }  . Q/ G2 B$ [8 S8 \  y( l
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
, @8 D! z" n$ J/ C/ N           require_once CACHE_MODEL_PATH.'member_update.class.php';  
! x6 w2 d' Q3 x& G* m3 v" y           $member_input = new member_input($this->memberinfo['modelid']);  ) P" v' L4 O& H2 b5 h
           $modelinfo = $member_input->get($_POST['info']);  5 x6 l8 |  e! R" H6 K3 T
           $this->db->set_model($this->memberinfo['modelid']);  0 X4 D7 N$ [# Q+ i& }4 X% O5 e
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
4 |" o2 Y( W6 g           if(!empty($membermodelinfo)) {  
! ]/ @6 q$ G, ~& N              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
. p2 L* Z) D" B, F# }           } else {  1 U3 K# x. G! F$ f  l1 \
              $modelinfo['userid'] = $this->memberinfo['userid'];  
* p$ a  c8 H% U- d; C/ v: B/ o              $this->db->insert($modelinfo);  & K) z2 y- U! P9 D8 j' M
           } ' x3 p. ^1 j9 g1 ^
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
+ z  u- u8 Y& b4 [0 Q在\caches\caches_model\caches_data\ member_input.class.php 文件中:
, Z6 Y% W. ~$ e: \$ q2 `+ m% o5 n+ D0 i: |8 b5 q6 B( x5 G

) b. X! j4 t1 K
4 m* t$ C5 a: y0 C. qfunction get($data) {  
( h7 B6 T7 y5 e+ W: x/ ?1 y8 s       $this->data = $data = trim_script($data);    E# v' J' k. s7 ]
       $model_cache = getcache('member_model', 'commons');  
8 ?* K/ y) a* n; d, @  t' T' F       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  3 k. H( @- h. [0 \7 Z
       $info = array();  
4 D  @8 O& e) R/ }       $debar_filed = array('catid','title','style','thumb','status','islink','description');  : w! q7 z2 U, N0 `5 E! F
       if(is_array($data)) {  
& k3 _) S- n$ i$ [* W' t" u           foreach($data as $field=>$value) {  
  h1 v$ S8 C- J7 Z              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ' z: F& K$ i, \6 A  [5 Y
              $name = $this->fields[$field]['name'];  
+ {# q5 `. I5 {7 U6 F) U- H6 V              $minlength = $this->fields[$field]['minlength'];  
8 n& J" L1 |! ~" L; i              $maxlength = $this->fields[$field]['maxlength'];  
  m: D  O; R* o/ i+ E              $pattern = $this->fields[$field]['pattern'];  
' Q$ z: H9 E7 i( }. @9 i$ Y2 U" D              $errortips = $this->fields[$field]['errortips'];  # y7 k) d; p( y9 s. \" [, _( N
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
# s, y0 J/ v% l- W              $length = empty($value) ? 0 : strlen($value);  9 d. D% g5 [0 N; Y) ~7 q. J( q
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ; F# C8 r; K0 r7 K+ @% h: m
              if($maxlength && $length > $maxlength && !$isimport) {  : P- x) v) P  {! F2 s
                  showmessage("$name 不得超过 $maxlength 个字符!");  
. U. ?! c9 m! B9 o! q              } else {  4 ?6 ~3 O! c# k, V2 t
                  str_cut($value, $maxlength);  
, n0 k8 J0 n, d6 S              }  
2 T. w2 h  J) T% \$ x/ g( H7 X              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
2 \( i! ]6 T. y                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  9 F) Y2 c; [/ H% J% Z
              $func = $this->fields[$field]['formtype'];  
1 ^5 L6 m* c) ^2 D' E! O* }              if(method_exists($this, $func)) $value = $this->$func($field, $value);  : l) Z. q  N, J+ x+ @
              $info[$field] = $value;  
' i  l/ v, |, m% t3 `1 a! r7 W  t           }  
# Y/ U( ~2 u' B9 k2 Q! J: e       }  * w2 b& L& h' o# p
       return $info;  
4 C1 k  n' |% q8 `    } + q; J$ J8 P* a3 o
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,& \" ~/ L0 R% h0 I+ l9 v  _

" T* T" w: c. V& c# \, n3 S再到phpcms\modules\member\index.php 文件account_manage_info函数
" B% E/ @/ r5 m9 o# {: m  M/ u4 _过了get()函数之后。0 a$ I! E5 m  {7 ]* B" W7 P

5 B$ D7 r/ `0 U
7 l0 N1 r- k# D6 ]# a  D$modelinfo = $member_input->get($_POST['info']);  
8 f" }' ?$ z' b1 k  d           $this->db->set_model($this->memberinfo['modelid']);  . W5 z- I/ @& q" N9 h9 _
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  9 _5 W: v# B2 D* ]* S
           if(!empty($membermodelinfo)) {  
6 `* ]! W/ B1 }9 h7 B* _              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  % n' \; k% Z2 L3 _. w% ^, z+ @8 k
           } else {
* Y5 l  S) c5 Q, j" b' E直接带入数据库,update函数我们跟进看看
: I* ?! b+ M& [& l+ c
6 M* I$ o( A2 t0 k* \  _3 g; X * B3 @1 j: V, |! l0 H( `* z
public function update($data, $table, $where = '') {  * f* a1 K7 D, l* f* a' V
       if($table == '' or $where == '') {  
/ \( ?0 Z% |& m           return false;  
( i! ?# y, f, v& n' ^5 X. C       }  
" d0 J/ e8 H/ x; [( A       $where = ' WHERE '.$where;  
+ a: o  ^# }! ?       $field = '';  , B$ B; N/ s! u' D
       if(is_string($data) && $data != '') {  
. h$ Z1 y* \; U           $field = $data;  ( ~2 t6 }4 a* g" D- e; u0 n" s
       } elseif (is_array($data) && count($data) > 0) {  
5 M3 G) F$ B, }           $fields = array();  , y7 H; q4 }, ]. {% D- j
           foreach($data as $k=>$v) {  
- j! p$ e& u- b. Q" M/ I              switch (substr($v, 0, 2)) {  ! \0 i+ Z; L: v! \
                  case '+=':  3 R# x. a1 R7 H6 B8 F
                     $v = substr($v,2);  % h# V6 Y0 `1 {" c) L. S, S
                     if (is_numeric($v)) {  
/ r5 p+ w+ C" f- o6 a8 {                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
2 S' C$ L, _. \- N! k9 |                     } else {  
$ ?! u0 p4 p9 n, N3 Z                         continue;  , @1 o0 a! X2 T% B' n+ A& ?6 T
                     }  6 C$ S6 c- h! p1 p" c
                     break;  
  \8 b) C) l$ u4 A, t                  case '-=':  
+ c8 B- b3 K8 W( {/ y8 `1 z8 E3 ?                     $v = substr($v,2);  ; N0 B8 R+ i; I$ X  V
                     if (is_numeric($v)) {  
* {- M2 u: `( X1 |8 q5 c# o5 {  W" K                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  - O  I: }" n( P5 z  Z
                     } else {  # J5 q, W+ S7 I& c/ g$ g- f
                         continue;  
& w- ?3 z! r9 Y  `) `7 v                     }  
8 W8 z: s  X! I. |                     break;  , k) b3 `! u6 W: K+ s8 s
                  default:  # p/ v( N% A6 R
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
$ y% f1 R3 i6 {" Z$ z4 Z2 T              }  
0 ]* A, `: O; \3 k- f8 s/ ?           }  
" a; C: ~  ]# P4 r           $field = implode(',', $fields);  " M) P1 x4 \; p6 b2 f
       } else {  & B8 S! K5 Q, }
           return false;  
( H  T1 P/ f( O+ j" |6 b5 H       }  
5 ~6 H0 G. m' x- R$ j- R0 r5 Y       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
! L2 F& w; U" U$ ?! {# K       print_r($sql);  
" g* Z5 _1 h$ R1 y; T; r' g' V4 D       return $this->execute($sql);  ' `& k! x9 k+ ~2 w
    }
, y8 ?: w9 W' v! e1 ^' ]" N% C" c从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
% j* j+ j8 G1 O# C/ M  o
( }) J- Q% Z& `1 y; d+ p* L攻击测试:9 U; y0 n# R% A- V: ?7 y
测试地址http://localhost
5 u' C) Q" j5 e  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句; U3 |/ q' o7 J

0 l5 ~; p# Q4 u" o7 D , y: m# F5 T9 @, E* @, K3 h
7 M# I: h7 t' V8 G' m
- T& }5 o, ~5 k5 e

1 {( W, Y: b2 e

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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