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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告6 e& U+ }, [" I" j; h
漏洞作者:skysheep3 P4 {, F, F3 I3 h9 F  m6 H( ~
分析作者:Seay
8 U' ?) ]. }  j& s" d  C* a: B: W! O5 a博客:http://www.cnseay.com/' P1 G# K7 H# S" b( q
漏洞分析:9 H: x+ m, ], X7 }' \# I, a# z7 Z, e  ~
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
7 p0 m. m3 x5 S! m  [+ v! Z0 f+ v9 Q3 p) y. f3 d

% T3 O" y) [7 |. a$ c1 c - l# O. }$ F$ B8 f7 l+ p& q1 i
public function account_manage_info() {  ; ]  T, `- M2 J0 ~% K) ?
       if(isset($_POST['dosubmit'])) {  
- ^  X" J7 F$ v; h( [+ M           //更新用户昵称  ' x+ _, K9 T7 A2 g  u* H4 e
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
" {. |6 \+ N3 x& }, _           if($nickname) {  
$ i) U8 [7 n- a1 |6 {4 P2 E: \. i5 S              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  7 C; V) W" J. W5 s" ^! l* y
              if(!isset($cookietime)) {  4 c( r/ ~9 V' u1 F" J9 J! J  ^: B
                  $get_cookietime = param::get_cookie('cookietime');  
- v5 q+ x9 ?% l5 q1 a% o) }              }  
3 A* [- l* b! S9 x; C              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
- U8 @) ]7 a$ h              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
$ ^1 Y4 m8 S. r* C8 v/ a1 h" V) G) S              param::set_cookie('_nickname', $nickname, $cookietime);  
1 Q( h$ P; G% t/ @! Z           }  $ }# X# `- t, r9 Y8 W7 j9 k+ \! x+ Q
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
, K" h6 u  O( Z3 V           require_once CACHE_MODEL_PATH.'member_update.class.php';  
" y) c- Q8 J  S, j9 h( w% Y1 w           $member_input = new member_input($this->memberinfo['modelid']);  1 J0 X+ ]+ F5 A/ ]
           $modelinfo = $member_input->get($_POST['info']);  
3 v* m' ]$ s  b7 b" M           $this->db->set_model($this->memberinfo['modelid']);  
$ r4 e0 w& ]1 u+ h/ I8 y           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  3 q1 ~5 e, }" H% v5 e) g
           if(!empty($membermodelinfo)) {  
3 H, R8 H1 ~% x, n6 S' I7 G              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  1 F% Q# m4 B! e# f3 e
           } else {  ' t* `! E6 M# ^. d2 |; W* _) }4 h
              $modelinfo['userid'] = $this->memberinfo['userid'];  
! y& f2 N& i- c1 V  a5 V              $this->db->insert($modelinfo);  ) d4 ^: E) {- {; V! F3 Q4 b" `: Q
           } * ?, \9 f9 ~2 D! ~) Z/ o& \- c% w0 u
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
" x( R! O0 t" T* ^$ X# {+ F$ F在\caches\caches_model\caches_data\ member_input.class.php 文件中:
2 j) r: M$ H; j. q& z2 e
; q8 Z8 ~! l* h+ }8 ?2 N9 n# V
; w" c1 r. a0 H+ k# j( |' M7 P( h
% G1 c& l* l( T) T5 Y( wfunction get($data) {  
4 d, f: |+ u. Y! N* q8 T       $this->data = $data = trim_script($data);  
- b- Q: ?$ S* ^4 ]1 Y       $model_cache = getcache('member_model', 'commons');  0 n. A4 _5 i! f  O1 p  U1 ~& W; n0 w
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
$ U- t# g1 A1 u& A; V/ T       $info = array();  " X8 A, l& z% X5 t
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
' A/ `8 m+ F! L9 x       if(is_array($data)) {  
, ]7 W( k- q5 Y5 k7 p           foreach($data as $field=>$value) {  5 @1 [' L, \' I3 D' Q) |- \
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
* {( n+ o+ F: N' Q  P/ H- t- M              $name = $this->fields[$field]['name'];  * d; C+ E# R) l; @6 u5 j4 V) h+ e" r$ _
              $minlength = $this->fields[$field]['minlength'];  1 {  c1 G$ @* _2 l
              $maxlength = $this->fields[$field]['maxlength'];  
+ T9 N/ j: u: R! \9 ^; H$ _              $pattern = $this->fields[$field]['pattern'];  
$ J( B3 c1 W  e& P! V" O              $errortips = $this->fields[$field]['errortips'];  
9 w& [5 f+ b! e: p. e% ?9 [              if(empty($errortips)) $errortips = "$name 不符合要求!";  # \& w' l+ I: P- ^
              $length = empty($value) ? 0 : strlen($value);  4 c9 T% u% `- K+ B* k8 }
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  ' T- [5 _. z( ]
              if($maxlength && $length > $maxlength && !$isimport) {  
: c' O1 ~+ C7 w                  showmessage("$name 不得超过 $maxlength 个字符!");  / d) T1 h) C2 [" l8 c/ s) i
              } else {  5 R, Z0 a% b  t/ ]# X, z
                  str_cut($value, $maxlength);  ! v8 t( Z# ~9 {5 |) p
              }  % ?3 p( U0 \# r* v3 j: ?/ Q
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
1 ~  ~0 c" _# o4 l1 |) z                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
. P, l" Y  H' v. {$ H: Z              $func = $this->fields[$field]['formtype'];  
" U" ?3 p8 V" |              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
( ]; h3 ?) u: }1 W  I! O7 |: }& h; [              $info[$field] = $value;  
& }; V+ n. C( W) w: ]" ]6 U1 }           }  
+ k. Z- Q# D# [" c: y: ]       }  8 K  v: V/ ]3 a5 p4 R
       return $info;  
, ~* Y' u" @( U( v' `* U# p    }
3 R+ }3 X+ Z( \+ w) Y, j) Qtrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,
3 ?* c" l/ V* a* h% \9 V
: Z. v9 D- l% v. K: U( g/ t再到phpcms\modules\member\index.php 文件account_manage_info函数
+ M* Z8 `) j, ^* V过了get()函数之后。
2 L6 p1 I. d- `* X2 U, H! h6 V4 Y! k) _1 o

5 c, t/ L4 W! |$ [- ~$modelinfo = $member_input->get($_POST['info']);  
, z9 ]$ _) ~$ f2 F. }/ k& H' V           $this->db->set_model($this->memberinfo['modelid']);  
5 b. F5 `  w+ k- f           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  4 l5 h2 J! {; }7 C& |4 H; d
           if(!empty($membermodelinfo)) {  " B/ J) k7 B& ~/ I2 y
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
5 Z9 b9 Z& ?5 Q% A* T! Y           } else {
% j7 h+ n% M2 M4 ^( v4 H8 G4 x- O直接带入数据库,update函数我们跟进看看
1 {2 N( X# G1 z+ H, W/ M9 K! e: ~
+ E% i  @1 N$ A5 ?! b
public function update($data, $table, $where = '') {  * e9 i- h! ]; g0 V
       if($table == '' or $where == '') {  ; a# }% N! s5 z4 ~
           return false;  
# V: B0 X: y& ]0 q1 M       }  
. b" A/ G6 C" `. y       $where = ' WHERE '.$where;  
/ g5 T# P3 c) {, V' I       $field = '';  
4 ?- x. K- y% D; N! `4 @0 ^       if(is_string($data) && $data != '') {  
5 Z0 A  l% h, ~+ t! p! X           $field = $data;  ) b9 S9 V: _& A: h
       } elseif (is_array($data) && count($data) > 0) {  4 b& D& }. E! P/ v
           $fields = array();  
9 O7 O  r4 i7 K& B* D& ~* l; ~) v           foreach($data as $k=>$v) {  
5 ]/ }& X% ~0 d              switch (substr($v, 0, 2)) {    A: w+ `- S" d! J" I7 T. h
                  case '+=':  
$ d8 T- l5 W% a7 ~; h/ g8 Y( N9 _                     $v = substr($v,2);  
1 i+ O' H  u3 R  h! W1 ~                     if (is_numeric($v)) {  
/ T' b2 U. I; L9 F7 U! U& {                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  1 S1 X4 g; y4 j& d+ Q
                     } else {  
8 N( x; R5 _% s  L! c4 v% J8 l                         continue;  
% ^& C/ b2 V, ~; W: p; Q% N                     }  
/ V1 W' x% B: B  O& ^6 U6 X$ V                     break;  
0 K2 c, m1 m  j0 R3 [                  case '-=':  1 J1 V% w. e: \0 s1 U8 f
                     $v = substr($v,2);  
' [+ d1 o7 t) y+ {5 t                     if (is_numeric($v)) {  3 V9 b+ @* P# [: c% G' L
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  , l9 w4 j% K' {
                     } else {  / D4 f' V- k4 M! w
                         continue;  " K& j/ p, l$ V' H/ _
                     }  ' t" K0 a3 S* L
                     break;  
' ~& n. E/ |% d                  default:  
4 w( N( @6 d: [) w                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  0 D2 [# R1 A! x, E, \3 {
              }  9 `0 U* Z6 o  k/ b' I1 e/ D
           }  
" g# [/ t; y% W           $field = implode(',', $fields);  " F$ X; @. m) W1 i2 L& W
       } else {  $ P6 h4 X9 w& ^
           return false;  % y' u* Q+ A! A" Q1 W' Q( O, l* ]
       }  5 H; p' x) m3 b) s
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  * y' t% ?8 v* T: K8 ~
       print_r($sql);  
5 j9 F! L% ]; K' d8 e0 W* N       return $this->execute($sql);  9 m! m0 W  j2 Z- j; K& U
    } ) n0 [! t. E/ z4 D! G- B
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。# f- s2 x5 ^* U( u8 i" ?0 i
& \( }# ?- A. g: U" E  s. H
攻击测试:
6 N  f# ^0 k+ G0 P! E5 c测试地址http://localhost
" ^8 K" @/ t7 N- J& x  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
+ l8 ~0 s3 ^# q/ Y7 q
+ @& \, `( ^5 U/ q2 U5 ?+ G 5 h9 f7 V1 x+ g) ^* c
8 c; c+ `' U1 W/ ?) n: _

" E7 ]7 Z3 ~% A1 z! g/ I! P8 ?$ N* l8 ], l. Y  {" F

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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