晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)5 _. H8 }9 o# b# K" h$ D
6 y7 ^' v8 s. l8 R出现漏洞的两个文件为:' b9 V6 `; Z) M
Include/payment/alipay.php+ r5 w5 ^4 d: j
Include/payment/yeepay.php
- W* E1 d7 t/ B$ n& P' q漏洞均出现在respond方法里,估计这两个文件是临时工写的。
, x: U; {' l' W# o7 f4 {* ?* }3 e4 D9 N: b: Y
Include/payment/alipay.php1 R) i5 b' f9 w. p
; }- m6 w: g- n) Z$ J" {......1 I! p9 h" c0 E7 }
function respond()- S) g+ |9 N% ?4 k* Y* W: Z9 i
{) F$ N3 M7 i: F+ Q
if (!empty($_POST))0 F* k! k# {( g9 x
{# S8 U( T' \& A% h( l# ~
foreach($_POST as $key => $data)9 a% L( |8 h; `5 K2 J
{
6 T4 o- U; U, \/ V/ q $_GET[$key] = $data;' y. t2 H6 E+ b
}
7 Q( f7 l* i5 @4 A" M }2 D4 s) M4 @1 a h6 k) J" B1 e. y" G" \
/* 引入配置文件 */: W5 S- Q; F6 X5 c
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';( e* n+ a9 q, N3 @' d: p( l
...... 5 V( n4 X. H& a) N
1 j. l1 T1 _2 E1 |
: l6 s: d0 _ n! N3 ]1 l大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
* i; @8 O/ b+ D3 h" l0 p- X" e. O1 ^% ]4 h/ U) {! V
Include/payment/yeepay.php
' u$ ] b2 K3 \( c1 y% u3 c" h
# q) I" l4 e( q4 c
- J- W/ x8 w/ |: k; |: N
! W) L/ U+ n& Y1 G c& T& S6 Q......
4 P& F& b! V1 {6 |- } function respond()
" ~- }; A/ P4 K7 \$ P6 q( y {% W8 W- B8 R4 [9 Y6 a
8 E6 d% _& ^1 x /* 引入配置文件 */
" G, B% I: o4 S/ I9 J3 B+ f require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';1 R' y: X' D0 r/ N n# B. }
7 F" ~% |4 m$ _6 i( _4 r
$p1_MerId = trim($payment['yp_account']);
: p# {7 p% _) G6 C3 a $merchantKey = trim($payment['yp_key']);
* P) r1 ^5 A" @+ p5 g* o: h- u......
# q; p& L- s9 n _4 {; h , b; H- O5 N, J5 L4 w& R2 B1 x
V1 k# o* E: ~7 i 1 f- a: T- ] r* C- |$ G4 h
, X) v% E% P& X% S, y V7 m
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。9 l( ~3 @. T* V* ^" c% E) t' X9 S
1 A4 {. g$ S( l5 }! ]: ^) H
这两个方法在plus/carbuyaction.php文件调用。
/ D2 k% M% D/ M9 ~- \8 |
- B0 R, M& u/ l% n* I3 A, W5 lplus/carbuyaction.php
3 z! x. }& f4 _1 u+ F
* ] H/ X! U& u+ T......( ^1 |2 H5 J* k) E) N( z S6 r* \
} else if ($dopost == 'return') {
% B; s5 A8 j4 B- K( a $write_list = array('alipay', 'bank', 'cod', 'yeepay');2 O1 n% A' W% r* ]
if (in_array($code, $write_list))
5 E" E1 E& e7 z$ h( ~4 k, L {6 W8 U5 V3 H+ |: d
require_once DEDEINC.'/payment/'.$code.'.php';8 E# c1 X/ V/ N) I
$pay = new $code;
% m2 q+ F1 \0 E2 N+ ]. j $msg=$pay->respond();
1 j" L) A+ b h$ B* U5 n ShowMsg($msg, "javascript:;", 0, 3000);) U6 {. j8 C8 q D. [
exit();
% O7 f3 _5 A; m4 _$ o3 A } else {9 C, i$ p5 {+ J
exit('Error:File Type Can\'t Recognized!');# z! T5 i. H. J8 F
}
( Y) I$ ~8 m8 |6 x7 ]9 `# ^* Y+ j' R$ E}
4 F6 F% j& X; p `- o& a......
5 v3 r' N3 X4 T8 |, {. t8 z* H* f! w
) ~- f/ {( p$ \
( C7 R3 y/ g% X! }: `0 O* E$ N* B ! e" q7 Y, o. e2 [1 i1 O8 e
6 v% _9 e$ b, F$ g5 Q; F4 L$ n 8 z) `& W, p' G4 _( p4 V* Q* @5 v
: A# l$ u# W$ y1 n" Z" s2 N大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。7 v) n; M0 s/ r: Q
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
% a# s- e: e6 S1 D8 u, W5 W- w, g y& q2 n4 {
回到include/common.inc.php来看看他的机制。" X" o# m M# ?$ h! x
2 ^9 _+ h' t5 @* b {
9 a- D" t" p+ i
$ c! T' ~/ s; L( H2 ~/ n......
9 }% \* s2 p- v% h2 {+ dforeach(Array('_GET','_POST','_COOKIE') as $_request), L8 L8 Q: n6 t# k$ y
{
' c4 S4 @, r+ O. r2 I( E. y8 q foreach($$_request as $_k => $_v) 7 n- f, P$ V( |2 _- Q8 i, S3 z
{
1 T- X" k3 W. _. g2 x) j if($_k == 'nvarname') ${$_k} = $_v;8 ]- f- O g7 K& N) H+ W
else ${$_k} = _RunMagicQuotes($_v); T" L; i8 I* [ d3 n! P
}
* _( e/ a" g9 b}5 Z- n" t2 i9 W. [/ P; [ r$ k
......
8 B, h) \. S* r* V( x5 d6 \) 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。暴路径:5 c& {! s' k5 S! ^ E9 ?6 w- H& Y
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |