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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告3 a2 s9 A+ D0 f) y1 A# v
漏洞作者:skysheep/ s6 p$ a' S. F. P; g
分析作者:Seay
2 @* ^" p( H) e& R8 I: q博客:http://www.cnseay.com/+ _8 e) H8 h( c: T& {1 Q2 ^
漏洞分析:
8 Z* |! z3 s8 W- E! G  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
5 ?; Z, N, x* P. _* t) z4 u8 I' n3 ^# K

/ g1 _$ B3 M" | 2 b5 U6 e# c" |5 L9 d% U2 J/ ?9 `
public function account_manage_info() {  
* ^8 ?8 O  R) z8 h' z5 P       if(isset($_POST['dosubmit'])) {  
0 @2 @( Z. s4 i# K           //更新用户昵称  2 X. k7 J2 N6 U) \; ~* U* S  O
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  4 U8 p: ], y! o* Q
           if($nickname) {  
- J, p( _: O# b/ [/ W              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  5 [6 n' _7 B4 U' b: K: o0 Y9 n
              if(!isset($cookietime)) {  
4 u5 ]) C' b/ x$ c1 C8 n                  $get_cookietime = param::get_cookie('cookietime');  
' f8 K$ T' U! z: B& c              }  
% k9 W6 s: S0 |. h8 B; n. @8 F3 }              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
$ E# j0 A, w/ J4 J$ k. D0 y              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
2 e$ V- b! p7 b9 Y+ P( v: d/ e5 _3 U              param::set_cookie('_nickname', $nickname, $cookietime);  % Q4 K" ]7 u- X# a2 D
           }  ) ], H1 z: s2 l5 p8 v
           require_once CACHE_MODEL_PATH.'member_input.class.php';  * M( s5 U* i: g. Y& ^( {
           require_once CACHE_MODEL_PATH.'member_update.class.php';  " D. M2 C& z" D4 ^5 B, v( r
           $member_input = new member_input($this->memberinfo['modelid']);  ) Q2 q$ u# s+ f3 R) [
           $modelinfo = $member_input->get($_POST['info']);  
; x6 S1 b0 _7 a5 s4 V$ `           $this->db->set_model($this->memberinfo['modelid']);  
) }6 D% m5 `2 h3 H( T. U: I: U           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
' ]# @  n- }: O# B% ]' y, `           if(!empty($membermodelinfo)) {  1 |+ w& P) ]9 B- ]: E) n! U$ r$ ^
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
. Z: R" U7 \* O& w           } else {  
% Z: t8 }. w! p' I# U              $modelinfo['userid'] = $this->memberinfo['userid'];  
; m' D' l: R) j( O1 n0 o- s              $this->db->insert($modelinfo);  
; q  x/ L8 N. p0 _: g5 q6 b           } 0 e5 V+ b% o/ Z
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,3 A& G; i/ c; _. ^' [/ J
在\caches\caches_model\caches_data\ member_input.class.php 文件中:4 @1 F. n' ?/ U1 r8 E7 y
4 L9 y5 @9 T7 i; c* r' F  q0 n
4 e1 v3 b3 w; ^4 b' ]

* ?# W* h7 P2 F& V0 D- L! ~" m( Gfunction get($data) {  # t0 y% X8 V7 V0 r1 e- ]
       $this->data = $data = trim_script($data);  
% Z# h0 t9 Q9 e       $model_cache = getcache('member_model', 'commons');  
7 |. N# t& j' p: y6 x       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
4 }* ]/ Z) Z( V9 Q- d       $info = array();  * q( N! q. d6 E" Z, W! _
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
  d* i& [) j. w  \  R       if(is_array($data)) {  
) u+ ^7 u6 s8 D, ]9 M           foreach($data as $field=>$value) {  : E: j/ w! z/ ]. D! p2 J
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
2 Y- p/ K5 W% Q+ A3 [( R              $name = $this->fields[$field]['name'];  + B5 J$ Q+ |  |
              $minlength = $this->fields[$field]['minlength'];  
5 C# C8 b7 z& `2 r+ z4 f) c6 W6 T              $maxlength = $this->fields[$field]['maxlength'];  6 ]  a7 R+ Y' u8 U. ~3 }5 x
              $pattern = $this->fields[$field]['pattern'];  * p1 s4 Z; [, f0 ?1 I
              $errortips = $this->fields[$field]['errortips'];  
5 J$ e1 L; ]+ ]              if(empty($errortips)) $errortips = "$name 不符合要求!";  
' B0 W3 ~) W( Y7 I3 M  M              $length = empty($value) ? 0 : strlen($value);  
: y' [" I5 s- Z7 \. O, m0 }" m+ G              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  1 M8 c. L% T' `2 I) d% @3 `# M) |8 U
              if($maxlength && $length > $maxlength && !$isimport) {  
" h& c5 u& M' @                  showmessage("$name 不得超过 $maxlength 个字符!");  
9 N) V0 u- b$ C              } else {  2 {. P) x$ T: R. Q. G* m
                  str_cut($value, $maxlength);  7 t) }1 c- N2 c7 h1 Y$ |
              }  8 k8 E; |0 A2 B( K& s
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  9 J2 I3 C, z2 Y* F' N
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  - I0 g$ [5 K4 ^7 y- n' J. T
              $func = $this->fields[$field]['formtype'];  
; ~8 M# }! a: U! Q: v  _+ \, Z* ^# ]              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
# K' Z9 O  Z( \8 h/ S              $info[$field] = $value;  
3 j4 y& l  |" K: f           }  
% x6 F1 A9 a3 V% E% N       }  . e" E% H5 c; _2 W9 z9 p7 S
       return $info;  
# m! M0 Q* V5 y    } , H# `) c- j5 L! i
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,- S, ?* S8 C4 t. G0 M
8 T3 H" Z# K. l& @
再到phpcms\modules\member\index.php 文件account_manage_info函数
1 T( P. F* z. }9 J过了get()函数之后。# ^, D: D/ e5 _& R, h6 _* h

: g. T" m% Y8 j& f+ B# S
2 V. L& [' V3 ~5 A3 H* D, \: ]$modelinfo = $member_input->get($_POST['info']);  
3 A( L* m! Z, H# v1 ]           $this->db->set_model($this->memberinfo['modelid']);  
% L8 p0 O, j- ~5 k6 D, B  W           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  * J3 o: L$ o2 q$ n) |0 U
           if(!empty($membermodelinfo)) {    P6 g6 J3 a/ q: p4 ]0 C! X
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
5 B- D: T* x* E! D           } else { / Y( |6 Y: d1 S5 G
直接带入数据库,update函数我们跟进看看
! e5 W: m# x/ b/ \& b. q9 L& M, [
' W4 y7 Z% T( _9 ]
0 t, u+ P/ [. C8 `( upublic function update($data, $table, $where = '') {  
1 ~) V- J) \8 _1 A3 J       if($table == '' or $where == '') {  2 t! s/ s; Y! ]9 k0 `2 ~; Q! G& C
           return false;  
. X+ t. L1 v) k" S       }  
$ |5 c& [9 Y- M       $where = ' WHERE '.$where;  ; J. `/ I2 u% Y3 g2 v
       $field = '';  3 O* T/ f7 S4 V. C/ U/ D7 l
       if(is_string($data) && $data != '') {  
9 T& s5 S% q" o+ ?3 x- A1 Q           $field = $data;  
6 \# Z& Y4 h6 i0 L( L       } elseif (is_array($data) && count($data) > 0) {  % f% l0 M0 S- D4 k2 K1 P
           $fields = array();  
5 v- ~, C; q  |" W           foreach($data as $k=>$v) {  
( C8 O  Z) d+ w- G5 f- z              switch (substr($v, 0, 2)) {  
, g. d( ~% A1 n; b, e8 z* x                  case '+=':  ) o; j( G( _8 f8 F/ s( k$ V; p
                     $v = substr($v,2);  
: l' ^" h7 v* \8 }% S; P( `% `                     if (is_numeric($v)) {  0 z, c+ X8 O- z7 ^+ d
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  9 b7 n8 O/ Q: l0 j3 Y, `! s- Z; X; d+ z
                     } else {  5 d" L: k7 @' X3 p
                         continue;  
. b8 d8 E% }1 |3 k% X& d                     }  
) S+ f) o. ?8 T$ F/ {                     break;  ( C4 X3 l; ]4 ~
                  case '-=':  $ {' p8 A7 b: x) _8 x
                     $v = substr($v,2);  + j1 I5 V+ [$ o2 a% V5 w: A
                     if (is_numeric($v)) {  
+ S. I3 z- z7 K5 G4 F, A                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
( `1 A% a* X. s+ l                     } else {  1 q5 f+ g( p  t. s: P* k( f: @4 _9 d/ @
                         continue;  . C8 Z# q2 B/ f& f5 g
                     }  + @4 T9 @( h5 c8 _3 g( w7 M( b3 @+ g
                     break;  9 J8 r, v7 q. T, T- H7 J& m5 P  ~
                  default:  
  Y# w. w* V7 k2 R1 S                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ' m( I: C3 n6 @$ {6 Q" x
              }  
9 n: ?4 L$ \& N2 N6 @: i" F* f% h           }  # c  m$ h/ C4 n  q1 y: g3 F
           $field = implode(',', $fields);  2 \; o( s6 g% I; W
       } else {  . K- t0 p: `/ q) {
           return false;  2 O) k1 o. E/ F; b  l; x
       }  
  P9 D8 w% e. R7 h( Z! F5 ]       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  2 X8 ^/ e0 _* u+ b2 D5 O/ @# N8 Z. s3 e
       print_r($sql);  
# J- ~: T- L4 f8 X4 W0 r0 z: {       return $this->execute($sql);  
" u! S6 j& z* M- Q    } : _8 B! F, w) |, `4 B
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
# P, L; v4 B4 P1 _" q$ c( Y
* d. b1 i' c1 U% J5 x攻击测试:* E9 Q2 i( x$ t; S2 ~. c
测试地址http://localhost
8 U( _& i5 F) n) D  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句# V7 H" |! S, t2 W2 P% X

4 g" @6 q  }# D. N: z- P % B0 C" T) P$ }
! g  O+ Y+ s; {; c; z

& q: {2 n/ a8 m, I' Q; ]$ H' I) ^

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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