提示:仅供进行学习使用,请勿做出非法的行为。如若由任何违法行为,将依据法律法规进行严惩!!!
前言
文件上传是互联网应用中一个常见功能,那么它是如何成为漏洞的呢?在什么条件下可以成为漏洞?具体的危害又有哪些呢?以下我们将进行介绍!!
文件上传漏洞也是web安全中不可忽视的一环,其对于web网站的危害性较大,要想防御好文件上传漏洞,我们就必须先学习如何利用并发现这个漏洞!!!
一、文件上传漏洞简要阐述
文件上传是什么?
对于绝大部分的站点来说一般都会具有文件上传的功能,例如:头像更改、附件上传等等。
总而言之,文件上传这个功能本身是一个正常的业务需求。对于网站来说有些地方确实是需要能够让用户进行上传文件到服务器的。所以说,文件上传本身是没什么问题的,但会出现问题的是在文件上传之后,服务器要进行怎么样的处理,要怎样解析这个文件。如果服务器端在这一块没有做好对应的防范的话,那么就很有困难会出现对应的漏洞!
为什么会产生文件上传漏洞?及其可能一哪些危害?
文件上传漏洞:一般都是代码中没有对上传的文件做合理严谨的过滤,导致用户可以利用此功能,上传能被服务端解析执行的文件,并通过此文件获得执行服务端命令的能力。
文件上传后常见的安全问题有如下:
- 上传文件是web脚本语言,服务器的web容器解析并执行了我们的脚本,从而致使代码的执行造成一定的破坏等等;
- 上传的文件是某些策略文件,例如:crossdomain.xml、htaccess等等,黑客这就可以利用起进行控制在该域下的行为;
- 上传的文件是病毒、木马等等;
- 上传的是钓鱼文件或者包含了脚本的图片,在某些版本的浏览器中困难会被解析执行,从而导致钓鱼与欺诈的现象出现;
- 将上传文件作为入口,进行溢出服务器的后台处理程序;
- 上传某合法的文本文件但内含恶意的php代码等等,然后利用文件包含漏洞进行执行这个代码。
文件上传漏洞攻击所需的条件
对于绝大多数的情况来说,文件上传漏洞一般都是上传了某个能被服务器解析并执行的脚本,也就是webshell。那么我们来具体看看要完成这个攻击需要哪些的条件:
- 上传的文件能够被对应的web容器进行解析并执行。因此,我们上传到的目录必须是有对应的执行权限,且在web容器的覆盖范围内;
- 用户能够从web上访问到这个文件;
- 上传的文件如果被安全检查、格式化、图片压缩等功能改变了原本的内容,则攻击无法生效。
二、文件上传漏洞的绕过
目前,文件上传主要都是利用黑白名单的思想进行防范的,以下我们将介绍一些常见的防御手段以及绕过的方法:
前端
1、客户端javascripe验证机制
客户端将会会对上传的文件格式进行一个检查。一般都是利用用户的浏览器前端页面上使用javascripe对数据包进行检查过滤,将不符合过滤规则的数据包禁止发送到服务器段。这一种方式一般最好绕过的,所有前端的验证机制都是不安全的,毕竟用户可控!!
绕过方法: 1、使用浏览器的插件,将对应的JS代码禁止或者删除即可;2、首先将需要上传的文件改成合规的后缀,而后利用burpsuite等抓包工具,在发送的数据包里再进行更改。这样子也可以绕过前端的JS验证。
对应靶场篇 ==> upload-labs 的第1关!
后端
1、服务器端MIME类型验证(白名单)
MIME类型是描述消息内容类型的因特网标准。如果服务器端代码是通过Content-Type的值判断文件类型,那么我们就可以利用抓包修改进行绕过了。
**绕过方法:**使用抓包工具修改Content-Type的值就可以绕过检测。
对应靶场篇 ==> upload-labs 的第2关!
2、 特殊解析(黑名单)
黑名单规则不严谨,在基于debian和ubuntu的apt-get安装apache,默认对于文件的解析规则,就可以使得某些特殊后缀名仍会被当做。PHP文件解析。例如:phplphp2/php3/php4/php5/php6lphp7/phtml。
绕过方法: 使用php3等后缀。
对应靶场篇 ==> upload-labs 的第3关!
3、利用.htaccess绕过(黑名单)
在apache里,这个文件作为一个配置文件,可以用来控制所在目录的访问权限以及解析设置。即通过设置可以将该目录下的所有文件作为php文件来解析。不过需要服务器端的配置上允许.htaccess生效、Apache开启rewrite模块、.apache配置文件为AllowOverride All(默认为None)。
在.htaccess中可写入如下代码:
<FilesMatch "xxx">
SetHandler application/x-httpd-php
</FilesMatch>
代码中"xxx"的xxx是我们随意输入的,意思是指在当前目录下如果任意包含该字符串的文件都会被当作下述规则进行执行;
SetHandler application/x-httpd-php 将符合条件的文件都以php进行执行。
对应靶场篇 ==> upload-labs 的第4关!
4、利用.user.ini绕过(黑名单)
首先,这里我们先补一下知识:
user.ini : 自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件仅被
CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用
.htaccess 文件有同样效果。
除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web
根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。
在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI
设置可被识别。
两个新的 INI 指令,user_ini.filename 和 user_ini.cache_ttl 控制着用户 INI 文件的使用。
user_ini.filename 设定了 PHP 会在每个目录下搜寻的文件名;如果设定为空字符串则 PHP 不会搜寻。默认值是
.user.ini。
user_ini.cache_ttl 控制着重新读取用户 INI 文件的间隔时间。默认是 300 秒(5 分钟)。
因此,这里当我们能够探测到攻击目标的php版本大于5.3时候,我们就可以尝试利用.user.ini文件来执行一些恶意代码了!
.user.ini
auto_prepend_file=xxx.jpg
当我们上传完成后,这里的意思是:当我们在含有该文件的目录下执行任一的php文件的时候,都会将xxx.jpg链接起来一起进行执行。 于是,我们就可以利用这种方法进行执行蕴含了恶意代码的jpg文件了。
对应靶场篇 ==> upload-labs 的第5关!
5、.【空格】.绕过(黑名单)
这里我们能够使用这个方法,主要是基于upload-labs靶场中出现的代码里的逻辑漏洞。至于实际情况下是否可行,就具体情况具体再看吧。
先让我们看看靶场的第五关的源码:
这一部分的过滤逻辑顺序是:
- 用trim 进行移除字符串两侧的空白字符或其他预定义字符;
- 利用deldot 删除文件名末尾的点;
- 获取自点开始的字符串,也就说类似.php;
- 将大小写进行了转换;
- 替换字符串::DATA为空;
- 将尾部空余去除;
- 进行与定义的后缀进行比较
那么,这里就存在以下这个逻辑漏洞:我们可以输入xxx.php. 【空格】. 。 那么按照上述的逻辑来看,在经历1后没什么变化。然后我们在2这里,会删除掉一个点,此时就变成了xxx.php.【空格】。继续下去,3、4、5也不会有什么变化。然后到6去除空格,那么最后就变成了xxx.php.了。由于,Windows下末尾是不允许是点的(Windows会自动删除),至此,就可以实现绕过了!!!
对应靶场篇 ==> upload-labs 的第5关! 当然只要使用这套代码逻辑进行过滤的关卡,都可以使用这个方法进行过滤。比如upload-labs 前4关都可以。。
6、大小写绕过(黑名单)
在Windows系统下对于文件的大小写是不进行区分的,因此如果黑名单中没有强制进行转化为统一的小写的话,那么利用Windows作为服务器的普通很可能会因为大小写而进行绕过。
绕过方法 ==> .Php 、.PHP
对应靶场篇 ==> upload-labs 的第6关!
7、空格绕过(黑名单)
这也是Windows下对于文件名的限制。不允许文件名最后是空格,会自行删除的。
对应靶场篇 ==> upload-labs 的第7关!
8、点绕过(黑名单)
这也是Windows下对于文件名的限制。不允许文件名最后是点,会自行删除的。
对应靶场篇 ==> upload-labs 的第8关!
当然,这里还可以利用其他的类似方法也是可以的:比如window对于文件和文件名的限制,以下字符放在结尾时,不符合操作系统的命名规范,在最后生成文件时,字符会被自动去除。比如:空格、点(.)、还有某些字符(例如%80~%99)
9、::$DATA绕过(黑名单)
这里也是利用了Windows的特性。在window的时候如果文件名+":: $ DATA"会把:: $ DATA之后的数据当成文件流处理,不会检测后缀名,(也就是说,会自动过滤掉文件的后缀名)且保持::$DATA之前的文件名,他的目的就是不检查后缀名
例如:
"test.php::$data ⇒ test.php
对应靶场篇 ==> upload-labs 的第9关!
10、双写绕过(黑名单)
这里,其实主要是由于源代码中将关键词换成了空。其实咋一看下是很安全的,但是这里还是有一个逻辑上的代码漏洞存在。即,如果不进行严谨的多次循环替换,而是只检查一两次的话,那么我们就可以利用双写(或者说多次)进行绕过了!!
绕过方法 ==> .pphphp 、.phpphp
对应靶场篇 ==> upload-labs 的第11关!
11、零字节截断(白名单)
无论是在c还是php中,00是可以表示结束符,所以当读取到00后就会把00后面的所有字符删除。在文件扩展名验证时,是取文件的扩展名来做验证,但是最后文件保存在本地时,%00会截断文件名,只保存%00之前的内容。
截断条件: PHP版本<5.3.4,q且PHP的magic_quotes_gpc为OFF状态。
绕过方法: 服务端将GET参数截断的内容作为上传后文件名的第一部分,然后将按时间生成的文件名作为第二部分。例如修改参数jieduan为1.php%00.JPG,文件保存到服务器时,%00会把.jpg和按时间生成的图片文件名全部截断,那么文件名就只剩下1.php,webshell上传成功。
0x开头表示16进制,0在十六进制中是00, 0x00就是%00解码成的16进制。当然了,其实还可以利用0x0a(换行符)来代替0字节截断的效果!!!
详细的解读过程如下:
实际上,我们上传的包是接收到这个save_path+filename 一起的。因此,我们只要在路那个地方写上xxx.php%00后,在上传的过程中服务器检查的还是filename里的文件名信息。因为,此时我们上传的文件是没什么问题的。因此,直接可以绕过这个白名单!!! 但是呢在后续的过程中呢,由于我们在路径那里加上了%00,因此当文件结合路径存在服务器时,就会把后面的filename全部截断,只剩下了.php文件!!!
除此之外,由于在上传路径信息的提交方式不同,我们还需要对%00做其他一些手脚。。 具体来说如下:
以GET 方式提交save_path: 因为get会自动解码url编码,因此我们直接使用%00即可。 详情参考第12关。。。
以POST 方式提交save_path: 因为post这里提交时候,是以字符串进行的,它是不会自动解码URL,因此我们需要手动进行解码!!!详情参考第13关。。
12、 服务器端文件头部验证
一般来说文件的格式往往不是根据文件后缀名去做判断的,后缀名一般只起到一个辅助的作用。文件的识别主要是依据文件开头的一段二进制,不同的图片类型,文件头是不同的。
绕过方法: 1、伪造文件头绕过;比如,我们可以将webshell文件的文件头改成图片的格式,已达到欺骗服务器端的目的。然后呢,再利用文件包含漏洞或者其他的手段,将该图片的解析格式当作PHP文件进行执行即可
对应靶场篇 ==> upload-labs 的第14~16关!
13、二次渲染以及条件竞争
二次渲染: 在我们上传文件后,网站会对图片进行二次处理(格式、尺寸,保存,删除 要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片(标准化)并放到网站对应的标签进行显示。
就比如,我们上传某个图片当作头像,网站一般会对头像的大小以及分辨率等等有一定的标准要求。但我们用户本地的图片却大小各异,很难符合网站头像的标准要求,因此为了方便用户和统一化,网站服务器会把用户上传的图像进行压缩裁剪等等,使得最终的图片符合网站的要求!!
对应靶场篇 ==> upload-labs 的第17关!
条件竞争: 竞争条件是指多个线程在没有进行锁操作或者同步操作的情况下同时访问同一个共享代码,变量,文件等,运行的结果依赖于不同线程访问数据的顺序。
就比如,在Windows中,当我们打开一个文件后,进行读写操作时系统就会占用该文件资源,此时是无法对其进行删除或则重命名等等操作的!!!(但是现在win10里,即使你打开了php这个文件,貌似依旧可以删除掉。。。这里可能是系统更新迭代,安全性变高了的原因。但是对某些在后台中允许这的程序,依旧是无法删除的!!!)
绕过方法: 利用burpsuite不断的发送数据包到服务器中,然后我们这边可以利用脚本,或则浏览器不断的访问,这样子就有可能访问到还未被删除时的文件。
发送到服务器端的php文件:
<?php fputs(fopen('yuan.php','w'),'<?php @eval($_POST["yuan"])?>');?>
对应靶场篇 ==> upload-labs 的第18、19关!
14、服务器系统的命名规则
例如,在Windows中对文件后缀中的最后一位是不允许出现点的,即test.php. ==> test.php
对于目录来说也有一定的规则,如果直接创建如下的路径就会默认退回上一个: …/test.php/. ==> …/test.php
除此之外,还有部分的零字节截断也可归属到这一块当中。
对应靶场篇 ==> upload-labs 的第9、20关!
15、数组命名
在某些服务器中,会使用数组来进行拆分上传的文件名,例如:
test.php就有可能拆分成:
name[0] = test
name[1] = jpg
然后这里,再利用代码进行拼接起来: name[0] + ‘.’+name[1]
因此,我们只要在对于对应的数组处进行修改即可绕过!!!
对应靶场篇 ==> upload-labs 的第21关!
webserver解析漏洞
解析漏洞,是指中间件(Apache、nginx、iis等)在解析文件时出现了漏洞,从而,黑客可以利用该漏洞实现非法文件的解析。
- Apache 文件解析问题:
在apache 1.x 2.x中会有如下的特性:
对于文件名的解析是从后往前进行解析的,直到遇见一个Apache认识的文件类型为止,例如:
test.php.rar.zip ==> test.php
由于,Apache不认识rar以及zip这种类型,因此它会一直遍历到后缀.php为止,而后就会认为这是一个php类型的文件!! Apache对于这些文件的识别主要是依据cmime.types中:
- IIS文件解析问题:
在IIS解析文件的过程中有一个和前面0x00字节截断类似的漏洞。即,由于Windows中会默认忽略 ; 的字符串:
xxx/test.asp;test.jpg ==> xxx/test.asp
这里 ; 就会将后面的内容进行截断,最终就会执行test.asp了!
除此之外,IIS还有这样一个漏洞——处理文件夹拓展名出错,比如:将/*.asp/目录下的所有内容都当成asp文件进行执行。
xxx/test.asp/1.jpg
这里,1.jpg也会被当成asp文件进行解析处理的。
不过,上述所说的问题有一个前提就算,服务器本地中确实存在着这样子的文件或者文件夹才行。
当然,由于IIS本身是支持PUT功能的,因此这里还可能存在着如下的漏洞:
如果服务器对应的目录支持写权限,开启了WebDav(put就是在其中进行定义的),且IIS服务器勾选了“脚本资源访问:的复选框(move能够执行成功)的话,我们就可以利用put的特性,即允许用户上传文件到指定的路径下。 然后在利用mov进行将只允许上传的文本文件进行改写为脚本文件,从而就可以执行webshell了!具体的过程:
-利用OPTIONS探测服务器的信息:(如果的返回的信息里说明支持PUT以及MOVE的话则继续向后执行)
OPTIONS / HTTP/1.1
Host:xxxxx
- 上传文本文件:
PUT /test.txt / HTTP/1.1
Host:xxxxx
- 利用move修改:
MOVE /test.txt / HTTP/1.1
Host:xxxxx
Destination:http://xxxx/shell.asp
- PHP CGI路径解析问题:
在Nginx配置fastcgi使用PHP时,就可能存在相应的文件解析漏洞,该漏洞与在fastcgi方式下,PHP获取环境遍历的方式有关。
PHP的配置文件中会有一个关键的选项是默认开启的:
cgi.fix_pathinfo = 1
这个开启后,在映射URL时候会有两个关键的环境变量:PATH_INFO和SCRIPT_FILENAME。以下举个例子说明:
http://xxx/test.jpg/null.php
在该URL中,test.jpg中含有对应的php恶意代码,而null.php是不存在的文件! 那么我们看看其是如何进行解析的:
首先,在映射URL时候:
PATH_INFO = null.php
此时,由于映射时候是采用递归路径查询确认文件的合法性的。因此,当SCRIPT_FILENAME查询到null.php不存在时候,就往前继续进行查询。此时,就会查询到test.jpg是存在的,那么最终会执行的文件就算test.jpg。但是由于我们的PATH_INFO(不会随着递归查询改变) 还是为null.php,因此在最终执行时候,九江test.jpg作为php进行执行了。
三、WAF的绕过
首先我们需要大致了解一下上传的数据包中的参数名:以upload-libs 第二关为例:
主要有以下几种:
Content-Disposition ==> 是MIME协议的扩展,MIME协议指示MIME用户代理如何显示附加的文件。 一般可以修改
name ==> 表单参数值。一般不更改
filename ==> 上传的文件名。 可以修改。
Content-Type ==> 这是MIME的文件类型。根据具体情况进行更改。
一般的绕过方法主要有以下几种:
数据溢出: 通过在数据包中写入大量的垃圾数据,致使匹配失效。
符号变异:由于一般字符串是由引号括起来的。因此,这一部分,我们可以通过利用去除引号来绕过。(因为waf可能是通过判断引号的,来确定具体上传的文件名的字符串位置的。)
数据截断:利用前文所说的零字节进行截断。
重复数据:原理和数据溢出有些类似,但不一样的在于这里重复填入的是能够正常上传的文件名。
详情请参照具体的waf靶场绕过。。
文件上传的防范
-
文件上传的目录设置为不可执行:
之前的执行条件中讲过,想要能够上传后执行对应的webshell,就必须要使得该目录具有可执行权限以及web能够覆盖这个范围。因此,当我们设置该目录不可执行时候,web就无法在该目录下进行解析并执行该文件了!以此就可以防范该漏洞。不过具体是否进行该设置还得看文件上传后这些文件的具体用途进行综合考量!!! -
多利用白名单进行过滤文件类型、二次加工:
在前面诸多的绕过措施中,绝大部分都是因为网站对于文件上传的类型过滤只采用了黑名单的思想。因此,由此可见黑名单对于实际的防范能力还是较差的。故,我们最好多使用白名单的思想进行规律的处理!!
除此之外我们还可以对文件进行二次加工处理。比如,对于图片的处理,我们可以使用压缩函数、resize函数等等,在处理图片的过程中可以进行破坏原本图片中含有的html代码! -
使用随机数改写文件名和文件路径:
根据前面的执行条件来看。若我们能够利用随机数进行改写,则就算攻击者上传了对应的脚本,也可能会因为无法找到对应的路劲以及对应的文件名而无法进行执行! -
单独设置文件服务器域名:
根据浏览器的同源策略,如果将文件服务器设置一个单独的域名的话,就可以因为同源策略的限制,使得客户端上传的一些脚本,例如:crossdomain.xml、包含javas的XSS利用等问题都可以有效的解决。
参考文献
- https://blog.csdn.net/weixin_44519789/article/details/116570426
- https://blog.csdn.net/ws1813004226/article/details/114434499
- 吴翰清-白帽子讲web安全