晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)
' r0 }6 V, e0 U1 |" H% V. D0 a* f& g: I* _/ x
出现漏洞的两个文件为:$ i' Z: [" ` }
Include/payment/alipay.php" c! O( |( M: b- o$ a2 ~
Include/payment/yeepay.php
/ N% C: `9 `* U- n$ U' n% L/ N漏洞均出现在respond方法里,估计这两个文件是临时工写的。" _! @( G" A3 _
* [' `( k* w, J" T
Include/payment/alipay.php# u& a- ^5 I' H9 O- K
3 a% `" m/ L, v! Y! Q....... T' F0 _; `# ^# f B4 j3 r/ Q" i
function respond()
' Q; {' T7 o4 [# e5 o {$ N& J1 @0 D2 X3 R/ B
if (!empty($_POST))
. g9 X0 Q# v( T {
4 Q" j! J: f4 K/ A foreach($_POST as $key => $data)
8 m: c$ d" C" k/ I" F8 j {3 r+ E: b( M5 x; m
$_GET[$key] = $data;3 H) k) j* S0 _! _' Z9 D& a" f' ^' ~
}
+ l" ?" X! W8 Z0 ` }
* U# H9 h, D. ` /* 引入配置文件 */
1 o) W+ \$ D+ E require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';$ V+ F( U! b4 e. j0 B
...... ' t8 s# n* B; Y7 ~! o
# a) P7 | V8 ?6 c6 q$ U+ s& \7 M7 y, \- D" P7 [( [
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。) ^8 Q# B2 v3 W# N$ u3 H# Y6 w
7 w' g6 t9 C0 _; f% _# g Q
Include/payment/yeepay.php
: l3 ]3 b8 L7 v* L4 ?: G# q4 }% ^- [0 I/ ]
8 J/ A: T: u& Y9 ^* u- v: c) A5 q6 g. ]. V5 e& u
......
- F) [ u, P# P& l# P6 H* h, g function respond()
5 d! w5 O4 D B; U {0 H0 u+ B- A; T2 z
5 Q8 P: ^7 `. ? J9 } /* 引入配置文件 */
2 S4 s, C5 m) q* U require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';0 _4 w) k2 j# F
! h2 Y, n( g. V9 @ u% U5 {# E' \ $p1_MerId = trim($payment['yp_account']);
" ^7 [1 m( j. p8 N9 C $merchantKey = trim($payment['yp_key']);
% I5 T; j: C+ ~! ]...... 0 C4 w' @ i: Y# u$ N: `3 V
4 i S9 K. N% R1 b- i& G
1 c+ v' v6 N# y, \
" A# v3 a$ \9 b. c5 F
( Y e6 Y& b2 i大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。
0 Y m) [* \( W2 F& j# w
# |1 x. f$ m5 `1 B1 X7 \3 n2 d# p9 P这两个方法在plus/carbuyaction.php文件调用。
+ k* N, G7 ?6 \) c5 |, D5 u# E5 ^( {+ j+ p. V
plus/carbuyaction.php
+ T% v& D7 x: ~6 N" F2 J8 S
8 D& x) t; n3 P$ W, W......1 g, l) I+ d- I' d# m- ?
} else if ($dopost == 'return') {
, [! y' W- ^: ^8 X! n! x& y# T& }2 s $write_list = array('alipay', 'bank', 'cod', 'yeepay');
+ T* N, r6 W0 m2 q( P0 j5 ^ if (in_array($code, $write_list))1 G* D% J; I7 @, f% I$ [( k, N$ @
{
9 n$ B3 c4 H+ V. D3 {' | require_once DEDEINC.'/payment/'.$code.'.php';
* f2 i( ?9 ~% d2 M6 F $pay = new $code;1 W3 F% v5 K- ^: g3 l3 m
$msg=$pay->respond();# R S' S8 [! E: v
ShowMsg($msg, "javascript:;", 0, 3000);
/ R' v/ \1 f/ e exit();
* z6 c7 {3 N! W1 e+ f7 p: K$ Q" j8 V } else {; l/ j- U& L% p1 N7 ~6 y* F
exit('Error:File Type Can\'t Recognized!');8 T% R' K. Y7 ~: P
}' Y$ D l3 n5 V2 e
}9 x- L7 h8 O3 o
......
- ~8 X+ Z# j9 W* E6 G' v1 J
, K7 ?; \3 g/ l N0 i) f" m! q+ n' {3 p& G9 _ J# |; L* n! u8 u* r
! l; R5 m; P/ H2 e
( R! G- p% [- U* k
* e& F9 ~" p1 J' E/ h0 {
% ^- D' d' W4 O% l
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。; B0 L/ n/ w9 m U5 Q. V
所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。( ?0 i; V9 @+ w8 ^
8 d0 X; v4 n8 H4 K, j9 X
回到include/common.inc.php来看看他的机制。$ u, F+ M! y8 \( b! ?/ {
: P( s. L8 P/ q; T( W5 b: R. K% R
' ] C4 V- a9 q0 y# z0 b/ `7 q4 D6 ~% w9 y* V
......
% I( u7 S# s2 mforeach(Array('_GET','_POST','_COOKIE') as $_request)$ H$ L) n7 m- D5 R
{
) @6 |4 \( _4 x4 ] foreach($$_request as $_k => $_v) ' P& \8 ~/ s3 \
{0 h. S5 M$ r, Q+ [' @7 f: Q1 Z& U
if($_k == 'nvarname') ${$_k} = $_v;
$ f# f1 o2 D! H" T else ${$_k} = _RunMagicQuotes($_v);
( e4 m0 g- T4 Q* C6 D: O# X) Z }) h- B7 L- v6 U: ]: A3 o
}
: @7 I/ p8 H( V. \, s7 O3 h( @...... % Y& r9 F, p, p
大概在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。暴路径:: g; m8 W) k) w! b6 C
由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |