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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告' M& }' u- U4 o
漏洞作者:skysheep; W( u# h: A5 W! E; E
分析作者:Seay
! v. Q( a7 Z* b2 J! \7 [1 D0 [博客:http://www.cnseay.com/& n& T( G+ B2 D: a* r7 G: }" \) w
漏洞分析:
  s9 R$ @3 q! r& w1 c- c  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
- }6 _) X( F. }2 n
: O6 P2 f: v2 }4 M. i" c4 T' _7 \7 Q- V. p1 [! E+ `

. C3 o) [; r# A2 Q$ Q/ K* B% ]public function account_manage_info() {  
5 B' G/ g3 I+ P. b& o1 S1 Z$ ^" F( H6 C       if(isset($_POST['dosubmit'])) {  & ]/ K! b; e2 J* O: g
           //更新用户昵称  
9 [( r8 H4 @' p( T( i6 g6 Y$ T           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
, C* O+ K& N! E) ^           if($nickname) {  
4 a$ R, I+ o/ [' a9 c, Z              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  " ^7 j% \; r( I; w7 }. d. c' {4 _- \
              if(!isset($cookietime)) {  1 g' J/ s9 K, i
                  $get_cookietime = param::get_cookie('cookietime');  + h: D  d8 g6 v( I, K1 G# f
              }  ; U( W% _1 @/ ]% s* `2 D! d
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  + O' r7 x" p1 ]3 _1 t! C
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
' @7 ?0 s3 m; @$ k! J              param::set_cookie('_nickname', $nickname, $cookietime);  % P5 L! G9 E( T: s5 T- j
           }  
1 K* o, `' h" P0 a0 A! W, W           require_once CACHE_MODEL_PATH.'member_input.class.php';  
7 K* t3 J; g: C  _9 c* H           require_once CACHE_MODEL_PATH.'member_update.class.php';  
* w- s7 u0 c9 z2 {           $member_input = new member_input($this->memberinfo['modelid']);    z0 R+ c  J, o, ~5 t
           $modelinfo = $member_input->get($_POST['info']);  
) R  a0 \) \9 W. Q: z5 l+ H           $this->db->set_model($this->memberinfo['modelid']);  + q7 U( u0 j; a2 t8 z  S
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  , n: f3 n" O3 u
           if(!empty($membermodelinfo)) {  
8 x! [  R: W- d+ g. d( L5 F              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  , E/ r' N/ x% \2 J, j
           } else {  ! K% x. x+ F! n: L6 w9 R
              $modelinfo['userid'] = $this->memberinfo['userid'];  $ R0 C/ V; w- Q( i. V
              $this->db->insert($modelinfo);  : Z" Y' j$ E# [6 J: S% s* d
           }
* P! A( ?% L: e6 ?, V- ?7 y+ y3 s代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,) Q# |) U% x% y1 h+ `
在\caches\caches_model\caches_data\ member_input.class.php 文件中:8 _1 C; [/ q+ L5 N! S8 E

8 N  P& p9 X' \3 D; I8 }
/ t3 F- w1 S; P0 G$ ]9 P3 e' ]4 G
. R0 C* m/ {% _$ S5 r  R# Cfunction get($data) {  * D) f6 C  b& z, v( m# p% X
       $this->data = $data = trim_script($data);  
* B; h6 e& {+ @, {4 I& E" C       $model_cache = getcache('member_model', 'commons');  
* i+ D2 u0 C9 e       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
: h3 B( M! m" R6 Q# W& c       $info = array();  - O% a/ K% _  W/ X
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
9 e' {( J- `3 D( r       if(is_array($data)) {  % ^7 S% |% I% C& X* `$ T3 e
           foreach($data as $field=>$value) {  
4 A* ~1 Y- N0 o& W/ g              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  $ r8 T" ~& P7 j: S- ]
              $name = $this->fields[$field]['name'];  ' x& ~# x  z. G. g( ~+ g* @
              $minlength = $this->fields[$field]['minlength'];  # u7 d1 `% A0 a- ?+ j
              $maxlength = $this->fields[$field]['maxlength'];  
! T, t: V0 e. T7 o              $pattern = $this->fields[$field]['pattern'];  
  e9 K/ c  u( T2 d              $errortips = $this->fields[$field]['errortips'];  : V, R. N5 U0 U/ F7 H' I
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; P* g7 W$ `/ d, h* [              $length = empty($value) ? 0 : strlen($value);  
$ _) b6 R$ v( |# p( a  n2 C% [              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  : L0 R  x4 f$ ~% @" K1 N/ o1 B
              if($maxlength && $length > $maxlength && !$isimport) {  
! H) O% I- O* Q* m* F3 B                  showmessage("$name 不得超过 $maxlength 个字符!");  
) A/ g; P( Y4 s* F# r3 P+ z              } else {  
0 q5 K: C" m, T1 m% _                  str_cut($value, $maxlength);  ' A: G. Z9 |8 w+ M- t) }1 h0 ~5 S
              }  ( A$ R* \3 v3 R- x
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  ' l) H8 d8 `# `4 Y
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
5 f8 T6 u. |# U1 w% C! W              $func = $this->fields[$field]['formtype'];  0 l5 d; d$ h& L7 I4 u
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
4 y  @0 l$ k* E2 c) d+ _7 \2 h              $info[$field] = $value;  5 x9 c+ ?, h" t. k
           }  
: L6 ~- _" N, W- D8 q  K* s$ Y       }  
4 G5 \: f/ C" F" B' W3 T/ q- X       return $info;  
6 K; O7 Y& \$ ]' s& ]5 R) E    } 6 Y6 P3 O  `- m" Y  X
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,4 }  [: k% s3 v7 }. u2 ?4 a0 D
. j% y* H% K" B% \( Q- u; K
再到phpcms\modules\member\index.php 文件account_manage_info函数
, Y2 t, ^, f% p3 H' L- z. X; j过了get()函数之后。; T/ s2 c. d# g: ^$ G9 ^; N
0 R2 L$ J6 y( x

+ ~" V5 J/ d; o$modelinfo = $member_input->get($_POST['info']);  
( b' H8 P) @8 P6 l* X           $this->db->set_model($this->memberinfo['modelid']);  
& ^6 @. Z; u  k- L' K& q( S3 j- F           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
1 P/ d* `) [+ Z. P/ A! a, U; r. g           if(!empty($membermodelinfo)) {  
; i( `0 D, k  W3 w  I. j+ I* Y              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  # C, v9 m1 L7 q3 ]: K( @
           } else { 8 u/ w* [& ^0 D7 J( o
直接带入数据库,update函数我们跟进看看
$ }' c$ @# D, ?  Y6 K/ B2 q. L
6 z  y# s4 i& T  E3 w$ ?" r5 t& g
: G+ X9 a# `! t5 \" l& npublic function update($data, $table, $where = '') {  + h1 Z) D; i+ Z9 q0 w7 j2 C- I
       if($table == '' or $where == '') {  9 _8 C7 `: ^& g& \
           return false;  
" y6 P) c- Y. _  I3 Z, F       }  7 R9 d& V/ W" R8 ]* U+ _' X
       $where = ' WHERE '.$where;  % D5 |& |' P. w" M
       $field = '';  / z- M1 d1 P& j* K. R7 E2 T
       if(is_string($data) && $data != '') {  # ~- b( i( n9 q3 q' @) O3 g4 F4 |
           $field = $data;  4 e" j# R3 r8 q3 k+ w
       } elseif (is_array($data) && count($data) > 0) {  + p  g9 C' e, ]' C* J& j) b
           $fields = array();  ! @6 b! _+ G2 a+ u- R
           foreach($data as $k=>$v) {  * t+ }. p8 P3 n4 p9 j
              switch (substr($v, 0, 2)) {  5 z/ y6 f4 Y/ w* Y
                  case '+=':  ) V& \( z- H, f' ~! q5 z  R- b
                     $v = substr($v,2);  $ z; p7 L7 K+ V; u3 b5 o
                     if (is_numeric($v)) {  / b$ {  ?4 O2 O4 ]9 i, A6 F
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  7 _* t& P/ P# I% j+ J$ d- f
                     } else {  ; `: W7 j% b4 C6 U7 s( `# }1 ^
                         continue;  
1 @. g7 P, H  V5 e                     }  7 M# F# G; a2 |
                     break;  
5 L, N- {" v7 _9 g& c                  case '-=':  # O& N9 I& o/ s0 O9 O) [) p8 L
                     $v = substr($v,2);  9 f/ q! }( ~& }& E- U
                     if (is_numeric($v)) {  
& K: @5 e$ m3 G, _9 H4 n7 d                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  1 o& U- o7 q8 M
                     } else {  
+ u" ]- X$ O  Q: s                         continue;  9 J' T4 _. e& R# Y
                     }  % h1 H* o$ \4 _
                     break;  ' W9 }( f/ |2 X( D. r/ N/ ?
                  default:  
9 W0 F! F- m+ ]* L3 M8 ]3 C% s5 i                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  6 s( Z- ~' {( l. y0 T* x
              }  
' v4 e3 N5 ]  c           }  
) F  Y. u# t/ J/ e, h           $field = implode(',', $fields);  
8 z) o" h" c) F3 t+ t& x) j       } else {  
3 k  g  B! G% m7 r           return false;  
$ g. m; W: m5 o2 }8 m" \# T3 w       }  7 N4 h/ s  V  T- _- b& c
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
, V$ H4 [9 H8 H' [       print_r($sql);  
: b; _3 d& a' j5 r       return $this->execute($sql);  6 X. O5 [/ l; B3 Z
    } 0 h: \6 [7 A( K5 U# `
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。, u. b# ]  `; z+ Z
9 u+ }9 y7 n7 P- a% E' P' w6 @2 r
攻击测试:
9 J% Q0 G% I( ?/ r测试地址http://localhost
7 A9 V8 O3 y+ T9 U, Z  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
. U# L2 E5 p. F! ?! S4 U
- U. L- \9 u* X: ]" t% V* |6 x4 C: K * M, y& w. M6 l5 P7 T# k
: E3 [# A+ ~" g& q9 b9 ?% w( T

5 a: v4 }- \) `2 W/ v$ z. Y
. p$ B  ~; `5 v+ r2 g* |

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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