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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
  e! b" m6 g) T9 Z/ U漏洞作者:skysheep
3 p9 |( M4 T; _8 i9 x* V4 O9 h分析作者:Seay2 d3 _3 t& b$ ?$ R% ?- U" _
博客:http://www.cnseay.com/* `/ N, p8 N0 n( U2 `' P
漏洞分析:; w' A7 }3 V0 j) X5 _
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
* L" T. D& p: c% F( R) e
* b" I# j% j/ D5 c: z8 u9 R& D' f& ~3 s) }+ l/ Y2 Q
' N; g- T$ g+ G
public function account_manage_info() {    y& h4 m% w. e( O- f( Z, x! M, p% S
       if(isset($_POST['dosubmit'])) {  5 a) Q5 r2 D6 J0 K: f8 ]
           //更新用户昵称  5 _/ B- m. l7 x9 \
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
4 n2 P# ^1 \. ?: X4 b, n" J           if($nickname) {  
% o1 P* h$ k5 A3 O9 [- l              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  . L1 M4 Q, S- L+ H
              if(!isset($cookietime)) {  & v; ^% [& D4 `0 M  a: v
                  $get_cookietime = param::get_cookie('cookietime');  0 U  b9 q4 ]- f8 }0 i' Y
              }  
- g! M" x8 e$ ~7 H0 C% U) [" t              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  & e7 a2 x5 j& h! y4 u+ b; z% K
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  4 g, W* d3 G: D8 d' e
              param::set_cookie('_nickname', $nickname, $cookietime);  
* U' {- m9 ~! H6 w$ S3 g4 ^& R" `+ {           }  ; u5 u2 @' @+ [2 d- K; c1 ?
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
) k+ `* ~' @) J. k. T" ~0 d           require_once CACHE_MODEL_PATH.'member_update.class.php';  , d$ B3 n2 l0 ~" [) C
           $member_input = new member_input($this->memberinfo['modelid']);  
4 G, C( V' H3 O- U- ?- e           $modelinfo = $member_input->get($_POST['info']);  1 V2 U6 g1 W% K: p) ^
           $this->db->set_model($this->memberinfo['modelid']);  8 a; {* q$ A8 ]. d7 s6 M
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ) O' k1 k6 K( ^+ u" q, o7 w5 w9 H  F
           if(!empty($membermodelinfo)) {  
! u* |1 c$ H) H: s5 V1 ~+ `              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
& a  N  e' P" C( L           } else {  . ?- j. U4 a7 d! I0 d( L9 m, U
              $modelinfo['userid'] = $this->memberinfo['userid'];  
$ i5 L$ O. u: W' j8 K              $this->db->insert($modelinfo);  9 b# t4 D. ]$ g$ [
           } * T: }5 n0 I! Q* ~* \1 [3 W6 f% w
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,- N  p, _; D) r. G% |6 p
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
, L' f- k6 m/ K- o( ?" Q0 Y4 W+ X- d& [
! D4 }2 P; g4 M0 w0 s/ K. L' \! a

3 J/ v/ d% Z% C! kfunction get($data) {  0 a$ W* y$ m0 K5 U, A
       $this->data = $data = trim_script($data);  
5 X* z5 S) U) K+ U       $model_cache = getcache('member_model', 'commons');  
2 C' q/ j3 m2 G5 r1 }       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  ( ?# \$ z7 w9 O5 f+ D
       $info = array();  
; ^  y# U* \( H4 O) [0 R% S       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
) d: g2 h6 }0 l4 b) Y       if(is_array($data)) {  / O5 O0 p( r0 J
           foreach($data as $field=>$value) {  & @& l  s: f. U7 [+ h9 T
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
, A7 V/ X3 m* o1 l- j; ~0 M              $name = $this->fields[$field]['name'];  
% B- e/ |9 v: J              $minlength = $this->fields[$field]['minlength'];  
/ i5 }: f( ]$ t& L0 M" q              $maxlength = $this->fields[$field]['maxlength'];  $ n+ H3 ^: l* g1 i
              $pattern = $this->fields[$field]['pattern'];  
+ Z& e8 q$ \$ ?( A9 }$ P              $errortips = $this->fields[$field]['errortips'];  5 ~+ \; r6 Y& \- w) \$ O- b
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
" }- W9 m. j! p# u+ P* x              $length = empty($value) ? 0 : strlen($value);  
; U0 y  D( a" ~' V4 [8 ~; n5 E8 b              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
2 J, R$ @% G9 q9 q+ o) Z) Y              if($maxlength && $length > $maxlength && !$isimport) {  7 |- o) ^- k+ G1 ]- x6 w
                  showmessage("$name 不得超过 $maxlength 个字符!");  4 W: L2 s" t) n6 l1 R3 H1 S
              } else {  * J9 }4 h' i9 n7 _# W
                  str_cut($value, $maxlength);  3 b. R( _6 U- k0 X" ?3 z
              }  6 w$ L2 U$ Q- Q% L' p
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
. R# [. Z  I$ n2 e                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
5 ?- G6 E- m, E              $func = $this->fields[$field]['formtype'];  
! t2 I5 d- s3 L) P# i              if(method_exists($this, $func)) $value = $this->$func($field, $value);  3 T% T% \8 H8 R. }- ~7 z
              $info[$field] = $value;  
* r* P4 J! t( R- o, q5 V           }  + N% {9 B7 F% Z1 ^  |
       }  
* \# Z/ i7 G* N       return $info;  / W7 w- v- Z4 `" X; h
    }
& l, p! r( A& D$ P1 Ktrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,& Z3 M" i- w; ~* p. `  \' ^6 \/ N6 a

3 y; n" z. a( Z. a/ Y  h. U再到phpcms\modules\member\index.php 文件account_manage_info函数
# x+ C8 A  t. z过了get()函数之后。
1 [  H8 B* k" j3 G' y) @* n8 F! p1 n' x/ S# s2 a

3 J; D. v" m' ^4 N) D" n  k9 i$modelinfo = $member_input->get($_POST['info']);  $ ]% O1 i  m+ t3 n1 Z0 C1 l
           $this->db->set_model($this->memberinfo['modelid']);  
; m$ i  ~! f3 F% F- E4 x) c           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  1 u, n& b8 J+ M
           if(!empty($membermodelinfo)) {  
+ ~- B% I+ x% Q4 u! }- U              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
! m! b/ l& L: _& ^  ^           } else {
+ @0 `* N% S$ g6 k( m( A) u直接带入数据库,update函数我们跟进看看( n8 G# T2 U8 ]  n* R: I

4 W  X" }+ C) Y! ]$ G* C2 W! B- c
# i) ?, `: k, F6 e# {public function update($data, $table, $where = '') {  # U5 |, s' j  l, L! |6 P
       if($table == '' or $where == '') {  0 X- A% O& }% _6 D1 d! J
           return false;  , @  Q: R- s1 B2 f) {6 Z
       }  ! ]- z8 {3 L' D3 f
       $where = ' WHERE '.$where;  * g' G1 [& q4 A( u0 J7 ]
       $field = '';  ( `% q: n! Q  |+ W6 a
       if(is_string($data) && $data != '') {  3 Y. {# m6 t8 B% a2 S
           $field = $data;  
: Z4 P2 n* i- n& M       } elseif (is_array($data) && count($data) > 0) {  
, n2 W" N- S8 x- l( \           $fields = array();  & ?# K$ Q3 T, N  X0 J$ D; w: |. ?
           foreach($data as $k=>$v) {  
  ]* Q  B$ K) X! _$ s4 h' L$ L              switch (substr($v, 0, 2)) {  . j3 t% M) P& {. x$ I) ~
                  case '+=':  $ R( P* u0 d9 K( O! f* D* }
                     $v = substr($v,2);  
6 B! A& n8 e$ n8 t! w$ i# F3 h/ q                     if (is_numeric($v)) {  
2 e; o1 v' R6 x3 j  M; c6 X- d: w                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ) V; a( |& F0 g
                     } else {  % G+ p9 `- P% @& Z% K" R, ?
                         continue;  
2 v4 a" }8 }$ y                     }  3 s% P) J' j# O8 U9 X( d
                     break;  
2 L1 b- t9 K: a! e. ~) r                  case '-=':  ; S8 F* H" Q) I: S/ [+ g- G  t
                     $v = substr($v,2);  
) _% T# H+ b' W' {+ w                     if (is_numeric($v)) {  . D7 ]. x5 b) _- a2 H/ v6 X
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  4 {% s+ n5 z& n( r' _& s4 ^9 \  l
                     } else {  + C, U6 s2 H$ U7 K
                         continue;  + X; A' R7 a( E8 I+ n
                     }  ) @3 }3 O  f  a/ D! B( c
                     break;  ) `( x2 b! v$ O" w  B3 J
                  default:  
6 a! q* x# h% m; v                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
# w0 S$ W5 B7 Z& `5 Z/ |9 w              }  ( v/ H2 S1 a+ M8 n
           }  " v6 T4 D' X3 [* m' X) z
           $field = implode(',', $fields);  $ x) ~0 ?6 P4 H) x/ L! C$ {
       } else {  
1 v, g5 P, D. P, y* b           return false;  $ J2 ~. C# B* |2 k
       }  
) g  M: r. d7 Z       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
+ z2 U% |# F4 x4 g' G- T% M! _4 y       print_r($sql);  : _% y9 u# E" ]" N
       return $this->execute($sql);  
& D9 J+ B, E, |$ x( P: f% [6 d    } ( m9 L+ {) I6 Q% W% l; X. R
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
. ?* R: G* u& L# Q# Y
) R2 ~; L3 O9 }% \- m; A攻击测试:( }+ k/ I2 i. m( M4 }& \
测试地址http://localhost4 ]( N& K  w7 _/ A
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句' F+ Y2 x' W# k

, p0 s5 T0 i. C! F
: m5 w# w" e/ g5 `, D' D5 _1 k* t5 @
$ z* K% d& N9 f

1 ?# n9 |% E% L( {6 m2 I; f

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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