晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)! O$ J( i; e+ t+ n/ p+ P
) w4 R: \: W9 S V) K- K出现漏洞的两个文件为: \$ L! {; N& s1 \2 k
Include/payment/alipay.php
3 j1 \" \" i( _9 GInclude/payment/yeepay.php
) y3 v" z" `) W8 T2 f/ Z漏洞均出现在respond方法里,估计这两个文件是临时工写的。" Q/ M1 p1 S. T5 A1 z5 q
( u x' v, P; m7 G: f" v" C W% ^
Include/payment/alipay.php9 h0 |( W0 V/ w8 g" R( O1 I
1 p+ ~3 ?7 M# ~. c
......
& `0 P* {3 z% e/ I5 i) D function respond()
8 D. `' V8 {4 D0 m1 ~ {4 }% Z x# U( x* p+ @2 E
if (!empty($_POST))9 A8 _8 z7 \4 L, D" j
{
8 K! \: t, l0 |; Q; p1 J foreach($_POST as $key => $data)2 T" M4 `; u1 p+ n( R5 J& r' {
{! i1 [% i `1 O0 s1 l# U5 ^5 x2 i
$_GET[$key] = $data;
# v; |# z* `; \. e3 X }
^( d: g: d! M! B$ A4 n }
, x7 r" j+ q/ T/ E' ? /* 引入配置文件 */- t* e9 ~. G- F' \
require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';. d% }9 ]( h: i6 B1 P" L+ f. Q I
......
+ d5 J$ O* i+ x( q/ L- G; J* D
# w5 a& P" N! ]1 V! g, F
3 c$ \' |8 X3 \. U1 ~1 w大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。( n& S% w7 _* \1 j+ ]. ^
; {/ k) z$ u8 E0 R* `+ E
Include/payment/yeepay.php$ u/ y8 `% N0 U: O, z7 `
6 L& l S7 ~( ?
6 N# t9 Q. B& ~% r; T1 x; q" f1 r
5 z, z0 _- E1 a......
Y% T# l6 v$ d) D function respond()
8 r4 v0 e) ~+ Q+ ? {/ _: w0 j0 I; ^+ C* N
/ ~6 w0 d& e. M4 t' ] /* 引入配置文件 */
3 q7 h4 X' }$ |3 m+ A5 w: Q require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';
- t! ]0 P, O) U, [4 h. [3 n - X- _6 w% E% }" J
$p1_MerId = trim($payment['yp_account']);& ~; P8 d; J# ]# u' z, T/ N
$merchantKey = trim($payment['yp_key']);: o! d0 b+ n) a
......
7 u# G$ g# J( N, b. b' k ! j+ }+ T2 q2 T6 Y4 P5 e: k
; u/ K5 V. M9 V% m8 B5 ]
! w# X9 o$ s. ?! T! v6 V; W
' J* n" f: s- v; [6 G9 _8 h3 X大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。, }, ^ }! N5 u! G( {; @* G6 C
2 x( Q5 n3 ?2 r这两个方法在plus/carbuyaction.php文件调用。4 a' R+ [- ~/ T; e t9 F, j
I5 v. ? T8 \! i* h+ K) U" X* tplus/carbuyaction.php% a$ t% {+ Z: A- x) U: f
$ k3 K% c( m! l0 D4 Z$ I* Z
......
' C, z* l: B2 M" p/ ~+ q} else if ($dopost == 'return') {
! H: T9 F# t" y U $write_list = array('alipay', 'bank', 'cod', 'yeepay');0 I4 X; j8 T- |: E$ H, A
if (in_array($code, $write_list))2 C1 i+ O5 o$ L# x$ T( D( Q
{
8 i! _0 m) C { require_once DEDEINC.'/payment/'.$code.'.php';
# ?* x- V9 B3 u. s8 q $pay = new $code;+ Q- L0 D2 t* i& g
$msg=$pay->respond();, l% o: V/ v6 ^# o
ShowMsg($msg, "javascript:;", 0, 3000);7 H7 n+ t% S" c+ _' f6 n7 i
exit(); 1 O, p) l8 S6 k" U0 c
} else {0 U# X1 t" U: L4 y; m1 U
exit('Error:File Type Can\'t Recognized!');
$ m( }, W6 ~, U* t }
4 ~! P6 W; R' w# x' H7 E4 Q9 \* B}
, H7 |8 K) w- w% N! \2 g, u3 G......
+ k* y2 |4 x8 Q5 o " H0 I$ S* T* Y* Z
! u& \. x* ~8 S
' D. Z! C5 t) V9 w% w5 c
! I$ n/ }' f% L3 \' ]( _& N/ y( N
+ H: ?) {+ r& x) O1 F) P. M; E( u
: U7 x) l7 D: e0 @, N1 ]( q5 @
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
3 M1 _9 r3 N; a% t& P% `. D所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
' U& T# l c# l5 I# A+ r% k) S* O* x" z. T
回到include/common.inc.php来看看他的机制。5 C: u; y% M) E( `+ j
1 [( I1 P) }, a6 z f* D ; Y7 p* Q, N8 W4 Z% @
' L% b; @9 z, s" M% N......- j# \1 N) C2 Y* }% \
foreach(Array('_GET','_POST','_COOKIE') as $_request)
# v' d8 c6 [( n6 \) B9 p{
! v/ o) t# O- G( z) u8 S foreach($$_request as $_k => $_v)
9 V& t8 O% o, n8 a; m0 s {
0 m# Q9 s5 {$ Q if($_k == 'nvarname') ${$_k} = $_v;- [1 t2 k# \" {, `% R
else ${$_k} = _RunMagicQuotes($_v);( g! G8 W+ u: C9 D& z% R
}9 P( f& [( m5 K3 i4 n& z7 @
}
* z3 K9 ^% D4 d9 `: A! `...... 4 m( R& ~; n8 [/ v* X4 J( ?
大概在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 J: |, k( k7 D2 N- X由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |