文件上传漏洞的攻击方法与防御措施研究

2019-02-25 13:14郝子希王志军刘振宇
计算机技术与发展 2019年2期
关键词:文件名白名单攻击者

郝子希,王志军,刘振宇

(1.东华大学 计算机科学与技术学院,上海 200050;2.上海计算机软件技术开发中心 上海市计算机软件评测重点实验室,上海 201112)

0 引 言

“互联网+”推动了各行各业与互联网的融合,各行各业大到工业、金融、商贸,小到娱乐、民生、家庭,与互联网的联系越来越紧密,形成创新2.0下的互联网发展的新业态。但“互联网+”在带动国内互联网经济的同时,也为通过网络传播的有害信息提供了更大的空间,攻击者的攻击手段也在不断更新。2017年6月1日,国家开始实施《中华人民共和国网络安全法》并对互联网和信息系统的安全做出了明确的要求,网络安全的防御工作更加迫切。

近年来,虽然国内几乎所有企业都开发了自己的Web应用系统,但是这些Web应用是重点致力于方便客户使用,给予客户更方便、快捷的服务支持,因此现在的开发人员更注重的是Web应用的功能和性能,而在非常关键的安全性方面,却没有付诸足够的重视。渗透测试指的是一种通过模拟恶意攻击者的技术与方法,对目标系统进行攻击,绕过或挫败目标系统的安全控制措施,从而达到取得访问控制权的目的,并发现具备业务影响后果安全隐患的一种安全测试与评估方式[1]。文件上传漏洞作为渗透测试过程中经常出现的Web漏洞,正在严重威胁着网络空间的安全。攻击者可以通过文件上传漏洞窃取服务器的信息,种植木马,在受害服务器网站上传播恶意信息,甚至获取服务器的管理员权限。

1 文件上传漏洞概述

文件上传漏洞指的是,由于程序员对信息系统中用户上传文件的模块的控制不足或者文件上传模块本身存在处理缺陷而导致的漏洞,攻击者可能利用此类漏洞越过其本身权限向服务器中上传可执行的动态脚本文件,并通过该文件对目标系统进行进一步的恶意操作。例如,某信息系统使用的是Linux服务器,并且以php作为服务器端的动态网站环境,那么在信息系统有上传文件功能的地方,就不能允许用户上传后缀为*.php的文件,否则攻击者可以直接上传一个php语言编写的Webshell,服务器就被攻击者入侵了。

文件上传后导致的常见安全问题一般有:

(1)上传的文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行;

(2)上传的文件是Flash的策略文件crossdomain.xml,攻击者用以控制Flash在该域下的行为,其他通过类似方式控制策略文件的情况类似;

(3)上传的文件是病毒、木马文件,用于诱骗用户或者管理员下载、执行;

(4)上传的文件是钓鱼图片或包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。

2 文件上传漏洞和常见的解析漏洞

在文件上传漏洞中,攻击者上传了一个可执行的脚本文件,并通过此文件进行进一步的恶意操作,这种攻击方法是最直接和有效的。但是通常在信息系统中,“文件上传”功能本身是没有问题的。但是如果攻击者上传的是php等脚本语言编写的恶意文件,那么就需要注意恶意文件上传后,服务器怎样处理和解释该文件。如果攻击者上传恶意文件后没办法执行,那么攻击行为是没有意义的。所以,文件上传漏洞一般和服务器中的解析漏洞一起存在。以下介绍几种常见的Web容器中存在的文件解析漏洞。

2.1 IIS 5.x-6.x中的解析漏洞

IIS的全称是Internet Information Services,意思是互联网信息服务,它是一个万维网服务器,意味着你可以通过IIS发布网页,并且由Asp、Java、VB脚本产生页面。使用IIS5.x-6.x的服务器大多是Windows Server 2003,运行的网站比较古老,开发语言一般为Asp。由于版本限制的原因,该漏洞只能解析asp文件,而不能解析aspx文件[2]。

该版本的解析漏洞有两个:

(1)如果存在一个以*.asp或*.asa结尾的文件夹,则该文件夹中所有的文件都会被解析成asp文件。

例如,在网站目录下存在一个folder.asp的文件夹,然后上传一个hacker.txt到该文件夹内(假如hacker.txt文件中存在Webshell),攻击者可以通过直接访问该文件在服务器上执行命令。

(2)IIS解析文件名时从前往后解析,遇到分号自动停止。

假如存在一个名为hacker.asp;.jpg的图片,则它会被解析为一个asp文件,若该文件中存在Webshell,同样可以被攻击者利用。

(注:asp环境下除了asp还有三种后缀的文件:*.asa、*.cer、*.cdx,也是可执行的脚本文件)

2.2 Apache解析漏洞

Apache解析文件时,如果遇到不认识的文件扩展名,则会从后往前解析,直到遇到认识的扩展名为止。例如,上传一个名为“hacker.php.aa.xx”的文件,由于Apache不认识.xx的扩展名,向前解析,又不认识.aa的扩展名,再向前解析,就会将该文件解析为.php文件。在Apache的安装目录下的/conf/mime.type文件中,有详细的文件名列表,它定义了Apache可以解析哪些扩展名的文件,如图1所示。

2.3 PHP CGI解析漏洞

在动态环境为php的服务器中,通过从客户端访问服务器端文件构造恶意的Url,也可以实现执行服务器上脚本文件的目的。假如在服务器中存在一个路径为www.test.com/123.jpg的图片,攻击者访问时在路径后面加上/hacker.php变为www.test.com/123.jpg/hacker.php,则服务器会将图片123.jpg当作PHP脚本解析。实际上Url最后的hacker.php是不存在的,所以路径中“hacker”可以是任意的。通过这个漏洞,攻击者将Webshell写进一张合法的图片制作成图片木马,并上传至服务器。上传成功后在该图片的路径后加上/xxx.php即可入侵成功[3]。

因为Nginx服务器通常作为php的解析容器,而Nginx和php配合很容易导致该解析漏洞,所以尽管该漏洞与Nginx关系不大,也通常被认为是Nginx的解析漏洞[4]。

图1 Apache可以解析的文件扩展名(mime.types文件)

3 针对不同防护手段的绕过技巧

3.1 针对客户端验证的绕过方法

客户端验证,就是在前端页面编写JavaScript代码来对用户上传文件的文件名进行合法性检测。这种验证原理是在载入上传的文件时使用JavaScript对文件名进行校验,如果文件名合法[5],则允许载入,否则不允许。

但是此类验证非常容易被攻破。攻击者使用抓包软件拦截HTTP请求,并修改请求内容即可绕过。例如,先把木马文件改成hacker.jpg的合法文件,成功载入到等待上传区,然后点击发送上传请求。用Burpsuite将上传请求拦截后将文件名改回hacher.php,再发送给服务器,则实际上传的文件后缀名为.php,实现了对客户端验证的绕过,如图2所示。

需要注意,如果HTTP请求修改前后的文件名长度发生了变化,那么在请求头中Content-Length的值也需要修改。Content-Length代表实体正文长度。例如,如果修改之前文件名为123.jpg,正文长度为200,修改后文件名为1.php,那么少了两个字符,Content-Length就要改为198,否则会上传失败。

由此看来,任何客户端验证都是不安全的。客户端验证是防止用户输入错误而进行的输入有效性检查,服务器端验证才可以真正防御攻击者。

图2 修改前后的HTTP请求

3.2 针对服务器端验证的绕过方法

3.2.1 绕过黑名单与白名单验证

(1)黑名单过滤方式。

黑名单过滤是一种不安全的过滤方式。黑名单过滤在服务器端定义了一系列不允许上传的文件扩展名。在接收用户上传文件时,判断用户上传文件的扩展名与黑名单中的是否匹配。匹配则不允许上传,不匹配则允许上传。黑名单验证PHP代码如下:

$Blacklist = array(‘asp’,‘php’,‘jsp’,‘php5’,‘asa’,‘aspx’);//黑名单

……

foreach (Blacklist as $key=>$value) {

if($value==$extension) {//判断是否为黑名单中的扩展名

$boo=true;

break; //退出循环

}

}

if(!$boo)

{……//允许上传}

else {

echo “文件不合法”;

}

……

?>

在以上代码中,黑名单定义的危险的文件扩展名有6种,但实际上攻击者还是可以绕过黑名单检测[6]。

(a)攻击者可以找到Web开发人员忽略的扩展名,如*.cer;

(b)如果代码中没有对扩展名进行大小写转换操作,那就意味着可以上传如AsP、pHp这样扩展名的文件,而该类扩展名依然可以被Windows平台中的Web容器解析;

(c)在Windows系统,可以上传如下文件名:“*.asp.”或“*.asp_(此处下划线为空格)”,在上传后,Windows会自动去掉文件名后的点和空格。

(2)白名单过滤方式。

相对于黑名单,白名单拥有更好的防御机制。白名单与黑名单相反,仅允许上传白名单中定义的扩展名。白名单验证PHP代码如下:

$Whitelist=array(‘rar’,‘jpg’,‘png’,bmp,‘gif’,‘doc’);

……

foreach(Whitelist as $key=>$value) {

if($value==$extension) {

$boo = true;

}

}

if(boo){

… //允许上传}

else{

echo “文件不合法”;

}

?>

虽然白名单可以防御未知扩展名的上传,但是并不能完全防御上传漏洞。例如前文提到的IIS5.x-6.x解析漏洞,攻击者可以把文件改为hacker.asp;.jpg来绕过检测,并执行木马程序。

3.2.2 绕过MIME验证

在HTTP请求头中存在一个Content-Type字段[7],它规定着文件的类型,即浏览器遇到此文件时使用相应的应用程序来打开。在上传时,服务器端一般会对上传文件的MIME类型进行验证,php代码如下(以图片格式jpg为例):

if($_FILES[‘file’][‘type’]==“image/jpeg”){ //判断是否是jpg格式

$imageTempName=$_FILES[‘file’][‘temp_name’];

$imageName=$_FILES[‘file’][‘name’];

$last=substr($imageName, strrpos($imageName,“.”));

if(!is_dir(“uploadFile”)){

mkdir(“uploadFile”);

}

$imageName=md5($imageName).$last;

Move_upload_file($imageTempName,“./uploadFile/”.$imageName);//指定上传文件到uploadFile目录

echo(“文件上传成功”);

}else {

echo(“文件类型错误,上传失败”);

exit;

}

但是,MIME验证也可以被中间人攻击[8]。攻击者用抓包软件拦截到上传文件的请求时,可以看到上传文件的部分的Content-Type是application/x-php类型,这样上传文件对于有MIME类型验证的服务器肯定是上传不了的。将请求这里的值改为image/jpeg,即可成功绕过该验证上传文件,如图3所示。

图3 修改前后的HTTP请求

3.2.3 绕过目录验证

用户上传文件时,Web程序一般是允许用户上传文件到一个指定的文件夹。不过有时Web开发人员为了方便,通常会做这样一个操作:如果用户上传的目录存在,则将用户的文件存入该文件夹;如果目录不存在,则创建该目录,并写入文件[9]。示例PHP代码如下:

//HTML代码


//PHP代码

if($_FILES[‘file’][‘type’]==“image/jpeg”)

$imageTempName=$_FILES[‘file’][‘temp_name’];

$imageName=$_FILES[‘file’][‘name’];

$last=substr($imageName,strrpos($imageName,“.”));//判断图片类型是否符合

if($last!=”.jpg”){

Exit(“图片类型错误”);

}

$Extension=$_POST[‘Extension’];//获取文件上传目录

if(!is_dir(Extension)){

mkdir($Extension);

}

$imageName=md5($imageName).$last;

move_upload_file($imageTempName,“./uploadFile/”.$imageName);

echo(“文件上传成功”);

exit();

}

//Upload.php中有如下代码

if(!is_dir($Extension)){

mkdir ($Extension);

}

在upload.php中的这一段代码是引发漏洞的关键点。在html中有一个隐藏的标签,这个标签标示的是上传文件时默认的文件夹,而同样该标签的参数对攻击者来说是可控的。依然可以用burp对请求进行拦截,对该标签的参数进行修改。例如前文提到的Web容器IIS6.0,将新建的文件夹的名称命名为123.asp并在其中包含木马文件,则可直接获得webshell[10-11]。

3.2.4 截断上传攻击

截断上传攻击的核心是“%00”字符,也被称为Url终止符,通俗的讲就是如果Url中包含这个字符,那么这个字符之后的所有内容都会被丢弃。同样在HTTP请求中也适用[12]。

//test.asp

<%

Username=request(“username”)

Response.write username

%>

以上代码的作用是接收username的值并输出。访问Url:HTTP://www.test.com:8080/test.asp?username=hacker%00admin,可以发现,输出的内容只有“hacker”,%00后面的字符都被截断了,这就是截断攻击的原型[13]。

例如,如下网页有一个文件上传模块,先上传一张普通图片,得到提示如果要得到flag,必须要上传PHP文件才可以。然后再上传一个1.php文件,提示*.php是不被允许的文件类型,仅支持上传jpg,gif,png后缀的文件。

针对这种情况可以使用截断攻击。先上传一个1.php_.jpg的文件(此处的下划线为空格,方便修改请求),在上传时将请求拦截,用Burpsuite的hex视图在上传路径的1.php后的%20(空格)改成Url终止符%00再上传,提示获取flag成功,如图4和图5所示。

尽管上传的是一个*.php文件,但是如果不进行%00截断,上传的文件在服务器上以<1.php.jpg>格式保存,也就是说这是一个图片文件,PHP无法解析这个文件。当进行%00截断后,服务器就会将%00后的<.jpg>丢弃,这时文件将以<1.php>的形式保存在服务器上,恶意脚本也就成功上传了。

图4 修改HTTP请求

图5 获得flag

4 防御措施

通过分析,文件上传漏洞形成的主要原因有两点:

(1)上传文件过滤不严,攻击者可能直接上传恶意脚本;

(2)攻击者可能通过上传“合法文件”,利用Web解析漏洞使之能够被执行[14]。

文件上传漏洞的防御,主要围绕以下几点:文件上传路径;文件访问权限;文件执行权限。另外,由于业务领域不同,根据上传文件类型的不同也需要进行不同的防御。以下提出了防范文件上传漏洞的几种常见方法:

(a)文件上传的目录设置为不可执行。只要Web容器无法解析目录下面的文件,即使攻击者直接上传了webshell,服务器本身也不会受到影响,这一点至关重要。

(b)判断文件类型。即前文提到的MIME验证,在文件类型检查中,强烈推荐白名单方式,黑名单方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize()函数,在处理图片的同时破坏图片中可能包含的脚本代码。

(c)使用随机数改写文件名和文件路径攻击者如果要执行上传的文件,则需要能够访问到这个文件。在某些环境中,攻击者能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击[15]。

(d)单独设置文件服务器的域名。由于浏览器同源策略的关系,一系列客户端攻击将失效:上传crossdomain.xml、上传包含JavaScript的XSS利用等问题将得到解决。

5 结束语

在服务器工作环境中,Shell指的是“为使用者提供使用界面”的软件,类似于Windows系统中的cmd.exe,网络管理员可以通过Shell对服务器进行一些管理行为的操作。而对于攻击者来说,文件上传漏洞一直都是获取服务器Shell的重要途径,对系统维护人员来说,文件上传漏洞的巨大危害,可以直接导致操作系统对攻击者暴露且被控制,并通过操作系统横向渗透入网络内部的其他设备。文中给出的方法基本可以解决上传漏洞,但不能说完全防御,因为没有绝对的安全,攻击者总是可以从不同角度对服务器进行攻击。所以,Web开发人员不仅要在代码层面对Web程序做好安全防护工作,更要对服务器操作系统、网络通信层面进行保护和严密的监控。及时更新服务器操作系统和WAF的补丁[16],对网络设备的日志进行及时、全面的审计,对用户的非法行为进行记录并做相应的处理[17]。不能只在某一个方面做好防护,安全是一个整体。与此同时,安全人员需要注意文件上传漏洞和其他Web漏洞配合所做出的“组合攻击”,这将成为今后Web安全研究的重点。

猜你喜欢
文件名白名单攻击者
基于贝叶斯博弈的防御资源调配模型研究
UAC提示太烦 教你做个白名单
右键调用多重更名更方便
Excel轻松提取文件名
2019年“移动互联网应用自律白名单”出炉
把我的秘密藏起来
正面迎接批判
正面迎接批判
移动互联网白名单认证向中小企业开放
船企“白名单”, 银行怎么看