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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
6 z  z1 j/ ^. ^! V& {9 }. g7 H漏洞作者:skysheep$ C8 n# Q  M. g8 y1 d
分析作者:Seay( a# W. x. e  r  V2 X& K1 V( C# K
博客:http://www.cnseay.com/# [& Y8 {) g3 C9 W4 Y$ S& M8 y, V
漏洞分析:4 U0 H2 Z" {3 i
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。- \' ]& D& N) Q% ?/ w) t

$ ]% k* x# K) P9 K8 i) g# V3 ~
; D( E9 r, H7 Q8 P( }' S/ a9 m) Y& x ( Y- p+ s+ x& e, E  F# |
public function account_manage_info() {  
$ R% k4 S; D1 U) `       if(isset($_POST['dosubmit'])) {  
5 ]  c3 T& T" L9 I5 k6 _  w           //更新用户昵称  
0 ~5 h# k  X( t" \2 e           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  : U8 Z/ O- b* q
           if($nickname) {  
2 c# O, D3 V3 h% l$ N              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
2 r/ K9 F) R6 _2 U5 z. G. N              if(!isset($cookietime)) {  , Q8 ^5 i3 U3 D! p, V
                  $get_cookietime = param::get_cookie('cookietime');  + a6 a) y3 V8 s' K3 K: {2 H
              }  
& d) F) S  C0 _7 @& T              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  / v/ i# h. C! V
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
0 H- r  [0 |* g' ?1 d  o              param::set_cookie('_nickname', $nickname, $cookietime);  
' f1 ~7 q) {* z( ]$ O2 U           }  
( f4 o% U7 s. I5 F: i           require_once CACHE_MODEL_PATH.'member_input.class.php';  
) \- M; T3 p0 w+ G           require_once CACHE_MODEL_PATH.'member_update.class.php';  - @5 P* i5 k  W( M  f: z# I5 }
           $member_input = new member_input($this->memberinfo['modelid']);  # k8 g% T1 O7 B9 }1 S0 ]( j
           $modelinfo = $member_input->get($_POST['info']);  1 h6 m" z. X, _9 m: f
           $this->db->set_model($this->memberinfo['modelid']);  
2 H1 {# Q6 y% w           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  5 ?( k1 G" R( u) G( v* ]8 k
           if(!empty($membermodelinfo)) {  
# |7 H5 \1 e; K' o, q0 C              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
) E% f1 D7 |3 z/ i; E           } else {  . K) k: Q& p4 M: V0 Z! U
              $modelinfo['userid'] = $this->memberinfo['userid'];  # O$ _) \$ L+ Y
              $this->db->insert($modelinfo);  
0 p+ T% n' R+ x& S$ T$ @           } - L0 m  f- I8 E1 x
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
& @' v+ U, u& X2 Z在\caches\caches_model\caches_data\ member_input.class.php 文件中:
6 ?6 A1 H( x" d+ y- \2 n: N8 r: q) z( ^3 [# P- o( |

6 O% ^& Y: Y" J
" k5 @& Q" Q) ]8 [% Y, V* ofunction get($data) {  
) x* _' F9 X5 y: X2 `       $this->data = $data = trim_script($data);  
9 z6 `) A* E6 X  A% X6 n       $model_cache = getcache('member_model', 'commons');  
/ ~3 v0 z+ }8 s; j) n8 w       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  + N+ |* _6 ~5 F8 z
       $info = array();  
4 R6 r$ Q- x) p* L3 G       $debar_filed = array('catid','title','style','thumb','status','islink','description');  - D2 P& M* S/ [- {, M$ G5 b/ o
       if(is_array($data)) {  4 k/ R% w' }. O( p5 s
           foreach($data as $field=>$value) {  
3 U) D; x' W8 c% t              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  * y/ X' V* h* N# s& I, L
              $name = $this->fields[$field]['name'];  7 P. @0 l6 o# D
              $minlength = $this->fields[$field]['minlength'];  ! t5 |: ]" |) `! l) V
              $maxlength = $this->fields[$field]['maxlength'];  % {" L5 y! V+ q  o% a! J. C, a
              $pattern = $this->fields[$field]['pattern'];  
! |% N, s  y5 q. R& L              $errortips = $this->fields[$field]['errortips'];  
+ o4 N; o$ l2 i, I: s              if(empty($errortips)) $errortips = "$name 不符合要求!";  ' X4 D, W2 e6 j! k0 W. K6 E
              $length = empty($value) ? 0 : strlen($value);  4 S* m/ G/ Q1 b5 x5 R
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  3 `) h. M* l1 ^8 O& T. g) \
              if($maxlength && $length > $maxlength && !$isimport) {  
: E- R4 w1 `* z9 Q6 c                  showmessage("$name 不得超过 $maxlength 个字符!");  
7 _. ?1 H1 t' p/ f6 A              } else {  1 _0 s) ^: `  C1 O7 {  o; d( ?
                  str_cut($value, $maxlength);  6 s2 C# c, h' Y- i! w
              }  
% Y- L  d# b9 `9 T" k# F  X              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
" W( x& \3 w3 y! u: I                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  . i/ U* P% U2 d" T( H
              $func = $this->fields[$field]['formtype'];  
. t, E$ Z/ s+ X! V1 P9 c              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
$ Y1 u- r2 J4 H* g6 ]. _4 e9 C              $info[$field] = $value;  & z7 U2 A) M/ n: U
           }  
% t# }6 O6 t$ W$ U       }  
9 R9 _( {4 @- S% O$ ~1 K6 E9 }       return $info;  7 M8 L, R' u, z, \( O
    } 0 ?2 T: N, W( K
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
' N$ x, X7 ~6 A! S" ?
4 @% m/ o& R+ c0 L0 _% s8 Z再到phpcms\modules\member\index.php 文件account_manage_info函数
) @' ^/ k6 k3 E. v过了get()函数之后。" |) _+ x6 y6 E
9 c% K3 j3 W4 H; g

+ S1 t3 F" J- E$modelinfo = $member_input->get($_POST['info']);  
; c' v, O( g3 R! \7 c           $this->db->set_model($this->memberinfo['modelid']);  : G5 S( `9 w& S) W- H0 V  N5 Q
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
; y, p6 _; i- q  R  q           if(!empty($membermodelinfo)) {  
+ @9 p3 J' R  O% b: p$ i) _              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
. |! f7 Y7 Q' k7 @  S- X" c- Q1 ^. G           } else {
/ C, H0 M! J8 M1 C: j( o' S8 i直接带入数据库,update函数我们跟进看看" b5 d! l& Y! L/ S9 [* P

6 Z7 q  L0 H% L6 C  v! E; P" R1 `
8 U" X: u, ^4 s: l/ w/ n: d, e  `public function update($data, $table, $where = '') {  
& s' ~8 X! W0 i3 Y) C, \* @       if($table == '' or $where == '') {    R+ K5 @) V) a/ }
           return false;  * Q) b/ b2 R0 I, w
       }  
5 P+ w" u4 j( p$ T8 \5 J& e. ?       $where = ' WHERE '.$where;  . d6 s* a" Z3 t$ c
       $field = '';  * I) ]; s1 T' }% y4 m# _! x+ v
       if(is_string($data) && $data != '') {  
& a( T' k* h. x4 p           $field = $data;  
5 j( A7 P0 J7 a3 y0 n) R2 o       } elseif (is_array($data) && count($data) > 0) {  
% A& ^! ]6 Y/ h, X           $fields = array();  
* x! U2 K. \4 B9 C, G7 H1 r           foreach($data as $k=>$v) {  
2 M- ]2 m: s! ], Y              switch (substr($v, 0, 2)) {  2 d' e! b" D+ `
                  case '+=':  
4 i3 G, R1 B  f4 j$ ?# s                     $v = substr($v,2);  
7 Q; d  @3 B. v; y: n* ]                     if (is_numeric($v)) {  
7 C( c( p( g6 ^  c9 w3 ^) A5 Y" q, S                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  ; F3 P" W+ G" w9 C4 B! T
                     } else {  
# V+ p3 ?' S1 ?, X9 j! [                         continue;  1 x7 |2 t! R7 ^4 R" S
                     }  1 {) u" a. ?( z2 J4 X+ Z5 ?! C! \
                     break;  / m$ B& ?) Y) H9 Y( P: D: Z
                  case '-=':  
. q/ p8 N% v* Y) ]* E$ f1 G+ \0 i                     $v = substr($v,2);  % @$ ?2 _* h6 N; ~, i. g& o
                     if (is_numeric($v)) {  4 `" @# E2 g! V( g5 F
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
7 v; m+ w5 t- M- P# F& T                     } else {  - Z+ N: O: U  I
                         continue;  # V. G) b; B6 e- |! Y) Y( l
                     }  
/ g! l+ Z* I6 F& V0 ~* y& p                     break;  + w$ E! {- Z6 B- R& H  V6 D
                  default:  # @) i% p  a+ p2 J! U) x' C3 k
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ! w0 l2 f: v* _+ n0 {) {5 t, r
              }  
# E  w( w' n+ E' C8 [           }  4 e) ]  m$ c" A6 E
           $field = implode(',', $fields);  
+ U6 }+ q) b; J% D3 p6 w       } else {  
. ]& F: d' z" c' f: k& O' b           return false;  
" d+ q. P- ~6 W( u2 h       }  
' [! ~* T! B" A2 h       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  
5 L" i4 W' z; Q  d) T& F, ~       print_r($sql);  
6 G8 y& l4 k6 C9 L       return $this->execute($sql);  ; l3 T* G; ]4 T2 @
    } 7 a% `3 \, h6 F5 y2 D2 k' [8 i
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。" b; y: |# c! |' W5 g
" ^  D5 S8 E- @) n7 A2 ^( d
攻击测试:
6 }  g4 `& B5 l测试地址http://localhost
7 s8 ]. b3 S) U9 g1 ^. z  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句- r7 y. s. _1 t! W% ?+ m8 p
* J, A7 {" m* q
! U" m; O3 z. o6 C8 K; e7 G
4 r0 a/ r# d" q9 f" e

% v# {- i) Y3 T+ v7 f7 k8 B3 C4 Z( K' u+ j" Q2 x& M4 r: D7 X& S9 q

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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