晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
, t, }/ F+ D( j5 j
" Q2 n1 Z; s/ v2 m出现漏洞的两个文件为:
, M, p9 _. S" a8 t- }& QInclude/payment/alipay.php5 }; R* h% b# ^" m$ B; o1 }" B! c/ l
Include/payment/yeepay.php0 E* [; {( M# L6 G7 ]
漏洞均出现在respond方法里,估计这两个文件是临时工写的。. g# E, ^2 `: R" `3 r$ }$ i
* r- h/ q0 g/ I4 @
Include/payment/alipay.php, y* \* K t$ H
# A* N! h( M2 o9 B( a: j......) T+ g( ]3 h& M6 s3 n
function respond()3 b4 }. n7 V" j9 w6 H4 Q0 D
{
3 [$ R- t* K0 H# N+ ` if (!empty($_POST)) W- `6 r p- G+ {
{! X3 R& ^2 J0 @5 K1 I. I
foreach($_POST as $key => $data); w# b; o& y/ K# W g3 s
{
3 p8 u6 ^( r- x- E1 b $_GET[$key] = $data; R! D) m# s1 w* K9 c8 Y
}
k2 p8 e( }' N6 E3 Z o+ ~ }7 M8 N$ Y7 L/ d+ P8 D0 U
/* 引入配置文件 */
@1 ]3 T' C+ I2 f7 |8 B7 I require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
# g$ j/ ]; e! a1 I......
4 W1 g7 P9 g( d
" @- z2 ?( Q9 E' |1 Z$ B( C' h7 `& n; s. {( |
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。. w5 H" \# [' |4 ?9 \) p
; L6 m8 |$ \" V: n/ L; n
Include/payment/yeepay.php4 R( E3 S, S( k7 { a$ [
& K6 m; ~+ n$ ~1 I( R$ r, l" w
% E; G8 A5 _8 c& `) k. g, B3 }; i- N% m3 \
......& a: I3 O4 h; R& c
function respond()
' ~5 h2 z: p8 {+ E+ _( }0 P2 V {
, j- G. {% n) d; h1 t5 z + n- {8 a2 g' w$ O
/* 引入配置文件 */! m8 S' b7 m# P' J# A' u
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';' M, ~* A; z/ Y7 ]' E6 \1 ^8 h, a( F
4 K M% M) R, \ B2 ~, {' V$ A s+ S $p1_MerId = trim($payment['yp_account']);0 ~5 u" H3 V. M$ z5 \
$merchantKey = trim($payment['yp_key']);
0 m, |" Z* ^. J& o# ]......
@! ?% ~6 T" o- B6 g ; f$ W$ n0 Z0 \+ E8 e2 b9 K
' K4 o# B( c* n5 [" H5 F
1 F6 ]0 ]# s4 s( W& L5 b- N" P4 I) E, [3 D6 }2 b
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。 @; q Y! E; Q# F6 ?( w( f/ M# S
, I5 d3 y. `) Y1 Y8 V这两个方法在plus/carbuyaction.php文件调用。
0 o! e9 u% {4 @% K; p* |, R$ M. v* [7 i
plus/carbuyaction.php
4 p/ H4 b D; B2 o) ~9 E( j" `3 K; p4 [: J2 h! M. X# s. j/ o
......: D* Z2 h4 G6 ~, z4 W. K. b
} else if ($dopost == 'return') {( Q/ s7 q4 @ v+ v9 j
$write_list = array('alipay', 'bank', 'cod', 'yeepay');9 r1 i9 W& w: p$ _" J
if (in_array($code, $write_list))5 ^/ `) }9 k$ ?9 d7 g
{
: }/ w( p1 [( D) f. \; Z require_once DEDEINC.'/payment/'.$code.'.php';% p5 {; w% q- e
$pay = new $code;
. Y/ ?: O) j' S( B. @ $msg=$pay->respond();7 U( z: O" y! \9 j( S
ShowMsg($msg, "javascript:;", 0, 3000);
$ J( e# ~, S8 }/ {/ I exit(); $ n/ g! x' f- B) y* b* |
} else {
$ o! h% m1 o* b1 A exit('Error:File Type Can\'t Recognized!');
, O2 _8 Q% p5 Z3 v9 i }
! ^3 V0 ]0 O, Q0 k}
% }6 [# u# o( X( Q......
9 N" J4 H, [' D: P6 `2 a5 x
# v; F. }5 d) r% @( T) E, _
5 B: f* ?( ?9 Z& P3 `: }8 [
" r# Q: O: ?7 ]& u% i
- a7 p* \/ }' b- j, Y/ A $ A5 T# a9 v, b, z/ a. F( ~
4 e$ A7 g1 L/ E; s# T3 @0 H- I& h大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。1 C/ w' W. i6 @( K1 Y
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。5 l t% h; n% d5 L: p4 r
: t' c- i- [% B7 o# b ?( ~回到include/common.inc.php来看看他的机制。 K% T9 k& b( }, n* W) {
3 i7 D2 v' t) y
' T, L7 [% b) g5 \' _4 y1 F2 n: a1 @
) z2 d3 c+ H; F/ ]# B7 u& k# R3 {/ D
......& o% H8 ~, u& p9 y: k6 d
foreach(Array('_GET','_POST','_COOKIE') as $_request)
* K4 ]& g0 f C{
' ]: w* ]% x8 B6 W& q foreach($$_request as $_k => $_v) 6 X+ k" V! ?. h) D
{
1 S p3 ^2 @$ j if($_k == 'nvarname') ${$_k} = $_v;# w' I/ x1 I/ l7 e) j" v
else ${$_k} = _RunMagicQuotes($_v);
X& M6 ^' }7 `3 [( x [3 _( T5 h# @ }
7 }$ a- A# z: a: _}+ s/ n1 V. J: a' V% k [4 @; J
......
/ o, N! C! r% I9 q/ Z' s大概在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。暴路径:
6 z Z# N' t v! e由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |