|
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告" v3 }8 w+ Q4 b5 X( H1 M# B
漏洞作者:skysheep& r3 S% u `( p* x+ P
分析作者:Seay+ H/ u2 t; R! E- f Y
博客:http://www.cnseay.com/4 z) l, z) C6 S4 I! k
漏洞分析:
/ @$ e7 v( u* y) X, \ 漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。" j: r' z9 `. T- z- M
9 Q! t p3 {) W6 S. m' j
+ T. a+ f- ~, s- Y, m0 Z" G9 b 4 Y( w5 a2 d+ ?* {' t- |2 z
public function account_manage_info() { 1 w! m4 z0 x' y
if(isset($_POST['dosubmit'])) {
9 R1 M) e j% f" R8 X //更新用户昵称
* Y" _' z+ b& K, s. I4 [ $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : ''; 1 @1 M5 c& U0 G7 [; U
if($nickname) { 9 [# q& K! l- g0 o; a5 G! m4 W
$this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid'])); 4 p8 [5 N/ ~ J5 O
if(!isset($cookietime)) { + F' D0 Z' o5 [! Z/ d6 q
$get_cookietime = param::get_cookie('cookietime');
- D6 U# ^3 [" c2 I, Q } 4 W: W+ {9 M, l3 j6 S
$_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0); 6 b; R, ]7 ^3 w s9 Y9 R* c
$cookietime = $_cookietime ? TIME + $_cookietime : 0;
& P8 }! v* W# N7 P& _, f param::set_cookie('_nickname', $nickname, $cookietime);
! T7 g/ c/ s9 W. s1 ~0 W/ |9 G" ] }
- Y9 ^" W8 e2 ^! s( F) _" k2 j require_once CACHE_MODEL_PATH.'member_input.class.php'; I- G; \9 [! W5 X0 m: b5 V
require_once CACHE_MODEL_PATH.'member_update.class.php';
0 n; q; u* x% O8 K c0 G9 ] $member_input = new member_input($this->memberinfo['modelid']);
0 h0 `; ~$ D {- M, @9 h* G3 `' L $modelinfo = $member_input->get($_POST['info']); ; V! f$ D1 Z2 j7 H% X0 o
$this->db->set_model($this->memberinfo['modelid']); - M6 R0 \; G: p( r' r+ R3 ]
$membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));
9 [; y* x d( G6 f- e- B! _& F% X- h if(!empty($membermodelinfo)) {
/ \8 `; C. r; G0 u' d; R $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));
& O" q) D% r: G* u6 N/ L( { } else {
+ F1 |' j6 ^$ Z, Z* y8 ` $modelinfo['userid'] = $this->memberinfo['userid'];
' t5 y ?, ]6 J& l1 T $this->db->insert($modelinfo); ( o. K1 v' Q' S& Q' S
} * n o' O$ V6 @& n
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
' |/ y4 `( p' K! W4 u在\caches\caches_model\caches_data\ member_input.class.php 文件中:
0 ]" [' C* S5 \2 L. Q2 W
$ [; \( L* U) r- X' w2 \# Q. q$ q- n+ l, G$ D$ s
1 Y7 ]2 @+ ^( a
function get($data) { : m( L6 Y0 `* a& ]
$this->data = $data = trim_script($data);
g" W" K& j. q0 S $model_cache = getcache('member_model', 'commons'); 6 k, |# b# ^4 j% J2 H
$this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];
. t& |; H$ r& O0 T! U% C& @% u2 Q$ S $info = array();
( v2 q% s# V- r8 G" l2 I $debar_filed = array('catid','title','style','thumb','status','islink','description'); # o$ _* l, Q9 T. O3 x5 U
if(is_array($data)) { & ]# Q# z6 z7 A+ J
foreach($data as $field=>$value) { : a" o+ K& h4 T0 W
if($data['islink']==1 && !in_array($field,$debar_filed)) continue; ' J9 E$ r$ Y( q( s' M% m
$name = $this->fields[$field]['name']; - m! e' y& V }8 z! M
$minlength = $this->fields[$field]['minlength'];
. t" X. C# ?8 F; I" Q6 v/ D $maxlength = $this->fields[$field]['maxlength']; $ J( c3 u" i$ ~
$pattern = $this->fields[$field]['pattern'];
1 M( ^/ {6 Q8 ?. V- g0 m: b $errortips = $this->fields[$field]['errortips'];
( b) J& Y7 `- W. t3 u% F if(empty($errortips)) $errortips = "$name 不符合要求!";
. J" n4 k* ^/ N* L* } $length = empty($value) ? 0 : strlen($value);
7 d* d# G: G" h8 t if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");
5 P2 R/ J6 C' @; X. p" x# q if($maxlength && $length > $maxlength && !$isimport) { G- ]# F+ O( T( Z8 V
showmessage("$name 不得超过 $maxlength 个字符!");
8 X9 J9 D9 |* e8 ?/ j } else { % Z8 E. d* F# F7 i; I
str_cut($value, $maxlength); 3 F. Y7 r, n- `4 ~, W' X$ B
}
1 }% s) ~8 Q" o0 x6 U% l3 Q: U if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips); ! h6 y4 J% r2 D: O$ \4 S) O7 T
if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!"); * z; N1 ]: q' K; l
$func = $this->fields[$field]['formtype'];
, `7 B+ P- j9 Z if(method_exists($this, $func)) $value = $this->$func($field, $value);
6 g+ {% Q% [3 y/ |+ M $info[$field] = $value; $ u( J3 N" Z. R d+ e
} . b, L5 i/ n0 a: H' z$ I! [
} . |4 K: K) b) A! d" W4 v
return $info;
( U" X" {( t$ H! j }
8 j8 E" y4 \& y0 Atrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,$ f+ }$ G5 f. F, r! `" i% K4 }
Q: [/ X# ~" ?. ]# ?# ~ {7 |再到phpcms\modules\member\index.php 文件account_manage_info函数" P2 L' [/ J2 w& s; o
过了get()函数之后。
6 `2 p. v! r( ^( J: h
$ U h% F8 n- h& O$ c # Z8 j( |3 ^: m0 d6 L
$modelinfo = $member_input->get($_POST['info']);
3 N- Z: t7 Q/ _, [' [2 y9 N $this->db->set_model($this->memberinfo['modelid']); " f% L$ {% Z/ |0 I! j" M8 {
$membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid'])); . S* {" F, V! _# O0 O2 m- s; ]
if(!empty($membermodelinfo)) { * q; N, X# t% y- \
$this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));
' I: C6 R/ z. f$ i' }6 r# l } else { 6 E3 M5 d% `* r, x* x
直接带入数据库,update函数我们跟进看看9 F% {) t$ M8 F
0 b2 C$ K2 A! k+ \1 c& u9 O6 p, }( K
, X! x+ C& J- o6 H1 E8 d% _public function update($data, $table, $where = '') {
* G: }5 y$ [$ X- ^+ [2 J& c if($table == '' or $where == '') {
) s+ m" U+ X; ]; O return false;
: f7 U" [+ ]1 d$ d3 V }
' n3 w+ ?4 |) s7 \; q, [ $where = ' WHERE '.$where; ( A4 K6 [& p+ h- Y2 n
$field = '';
% Q, q* C3 w+ e8 u0 f8 o0 F9 A if(is_string($data) && $data != '') {
/ x9 r$ M( L) A& q& { $field = $data; % Z" V0 U: `, n- g
} elseif (is_array($data) && count($data) > 0) { + S6 _+ Q0 z! R0 ?( _
$fields = array(); 0 v, X0 X+ ]2 y [& m& E. V3 [
foreach($data as $k=>$v) {
* r) H6 L0 _9 Q6 [0 _& \+ K6 l switch (substr($v, 0, 2)) {
! J k5 X! k. B7 `7 C* u' V3 ` case '+=': 4 r: Q0 z+ o3 J/ w* v5 N. a
$v = substr($v,2); # E) N4 m4 i( N
if (is_numeric($v)) { / p4 A# j5 n& T
$fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false); ' m+ j+ l v% T3 y
} else {
/ ~ H: l" X; } continue;
7 d" Q1 [# T* h; U+ c% K& i. D } # l. n6 C" F! E% [( e6 a$ d! J
break;
; v2 H' p1 h- J$ ]4 G case '-=':
, g3 ^2 C5 e) t7 h) T; k, Z $v = substr($v,2);
+ x3 e! G( i1 ]+ @: u* O3 H if (is_numeric($v)) { & o7 y3 E) Z0 N- ]( Q6 |
$fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false); , H' i2 h% D3 O4 o
} else { ) h/ y5 B% N) w
continue;
0 ^" t7 K O' _; ]8 O/ u6 G) X+ t }
) [: z. `' N) u3 g0 A break; 6 o) W, x- j/ Q/ u4 |+ U: u
default: # M2 \/ o' D% x* P& H! \
$fields[] = $this->add_special_char($k).'='.$this->escape_string($v);
. j2 l# T2 F: g. T; c }
* ^1 r$ u- V& H" i }
" G1 r% @ a5 P3 H9 Z $field = implode(',', $fields);
- `) @3 }8 N9 \, F1 C } else { ! T% }% a! s S/ ]# w
return false; 2 U5 I% U& {) k$ n
} * j+ l: O3 t0 t
$sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where; # m. e/ [; D( U
print_r($sql);
, I: {" r2 I R! a8 [0 h return $this->execute($sql); 0 t v& d2 ~. O
} + B& W# h( P7 Q S) M
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。+ j! p" e% a, g/ g. a: o
6 h( _( [5 D% ^$ y/ O; C6 a
攻击测试:
- m K0 t! Z% v' M) R7 b5 i6 x测试地址http://localhost
' x7 E. I) k9 L 注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
" Q4 w2 Z% C% T% L4 ?& R
( j2 p4 t" T2 p7 c) t# r+ w. @3 N ' m" L" v8 t+ N2 Q h
4 z! f0 Z0 |- J7 K3 y9 \
7 ~7 Y( M. G. M7 i6 u5 S2 Y
, k" J# [0 ?3 A7 S5 b0 d# s/ J |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|