一、文件上传漏洞介绍
通常web 站点会有用户注册功能,而当用户登入之后大多数情况下都会存在类似头像上传、附件上传一类的功能,这些功能点往往存在上传验证方式不严格的安全缺陷,是在web 渗透中非常关键的突破口,只要经过仔细测试分析来绕过上传验证机制,往往会造成被攻击者直接上传web 后门,进而控制整个web 业务的控制权,复杂一点的情况是结合webserver 的解析漏洞来上传后门获取权限。
二、验证方法与绕过
1.1CONTENT-LENGTH验证
Content-Length验证是指服务器会对上传的文件内容长度进行检查,超出限制大小的文件将不允许被上传。虽然这种类型的验证不是很受欢迎,但在一些应用的文件上传中也时常能碰到。
示例:
1 | if ($_FILES["fileToUpload"]["size"] > 30) { |
1.2CONTENT-LENGTH绕过
- 针对这种类型的验证,我们可以通过上传一些非常短的恶意代码来绕过。上传文件的大小取决于,(Web服务器上的最大长度限制,我们可以使用不同大小的文件来fuzzing上传程序,从而计算出它的限制范围)。
- 如果截断上传文件最大大小,修改文件大小的限制,然后再发送给服务端。
2.1客户端javascript 检测(通常为检测文件扩展名)
顾名思义,就是在文件被上传到服务端的时候,对于文件名的扩展名进行检查,如果不合法,则拒绝这次上传。
有两种策略:黑名单策略,文件扩展名在黑名单中的为不合法。
示例代码:
1 | $postfix = end(explode('.','$_POST['filename']); |
白名单策略,文件扩展名不在白名单中的均为不合法。
示例代码:
1 | $postfix = end(explode('.','$_POST['filename']); |
2.1客户端javascript
黑名单绕过:
通过上传不受欢迎的php扩展来绕过黑名单。
例如:pht,phpt,phtml,php3,php4,php5,php6。
白名单绕过:
通过某种类型的技巧来绕过白名单,例如添加空字节注入(shell.php%00.gif),或使用双重扩展来上传文件(shell.jpg.php)。
此外,我们还可以尝试扩展名大小写来绕过,例如:pHp,Php,phP
白名单策略是更加安全的,通过限制上传类型为只有我们接受的类型,可以较好的保证安全,因为黑名单我们可以使用各种方法来进行注入和突破。
3. 服务端MIME 类型检测(检测Content-Type 内容)
如: content-Type:aplication/x-php
绕过方法:
改为如下类型:
1 | Content-Type: image/jpg |
1 | 常用的MIMETYPE表 |
4.分析文件头内容来检查文件类型
一种检查类型的方式是使用对于文件内容的验证机制,这种方法利用的是每一个特定类型的文件都会有不太一样的开头或者标志位。可以通过比如php的exif_imagetype()函数
一个通过这种方法来过滤的示例代码如下:
1 | if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) { |
绕过方法:
给上传脚本加上相应的幻数头字节就可以,php引擎会将 <?之前的内容当作html文本,不解释而跳过之,后面的代码仍然能够得到执行比如下面:
(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)
1 | GIF89a |
图片文件通常有称作幻数的头字节,我们来看一下几种图片文件的幻数:
(注意!下面是二进制而不是文本格式的数据)
JPG
PNG
如果是其他类型的二进制文件,也有响应的头字节,如下表
格式 | 文件头 |
---|---|
TIFF (tif) | 49492A00 |
Windows Bitmap (bmp) | 424D |
CAD (dwg) | 41433130 |
Adobe Photoshop (psd) | 38425053 |
Rich Text Format (rtf) | 7B5C727466 |
MS Word/Excel (xls.or.doc) | D0CF11E0 |
MS Access (mdb) | 5374616E64617264204A |
ZIP Archive (zip) | 504B0304 |
RAR Archive (rar) | 52617221 |
Wave (wav) | 57415645 |
AVI (avi) | 41564920 |
Real Media (rm) | 2E524D46 |
MPEG (mpg) | 000001BA |
MPEG (mpg) | 000001B3 |
Quicktime (mov) | 6D6F6F76 |
Adobe Acrobat (pdf) | 255044462D312E |
Windows Media (asf) | 3026B2758E66CF11 |
MIDI (mid) | 4D546864 |
5.文件加载检测
一般是调用API 或函数去进行文件加载测试,常见的是图像渲染测试,再变态点的甚至是进行二次渲染(后面会提到)。
对渲染/加载测试的攻击方式是代码注入绕过;对二次渲染的攻击方式是攻击文件加载器自身。
先说下对渲染/加载测试攻击-代码注入绕过,可以用图像处理软件对一张图片进行代码注入。用winhex看数据可以分析出这类工具的原理是在不破坏文件本身的渲染情况下找一个空白区进行填充代码,一般会是图片的注释区。对于渲染测试基本上都能绕过,毕竟本身的文件结构是完整的。
但如果碰到变态的二次渲染,基本上就没法绕过了,估计就只能对文件加载器进行攻击了。
一般进行遇到二次渲染,想绕过,它相当于是把原本属于图像数据的部分抓了出来,再用自己的API 或函数进行重新渲染,在这个过程中非图像数据的部分直接就被隔离开了。能想到的一个思路就是基于数据二义性,即让数据既是图像数据也包含一句话木马代码,就像shellcode 通过数据二义性绕过IDS 检测特殊字符一样的道理。
如果要对文件加载器进行攻击,常见的就是溢出攻击,上传自己的恶意文件后,服务器上的文件加载器会主动进行加载测试,加载测试时被溢出攻击执行shellcode比如access/mdb 溢出如果要对文件加载器进行攻击,常见的就是溢出攻击,上传自己的恶意文件后,服务器上的文件加载器会主动进行加载测试,加载测试时被溢出攻击执行shellcode比如access/mdb 溢出。
总之对文件完整性检测的绕过,通常就直接用个结构完整的文件进行代码注入即可没必要再去测到底是检查的幻数还是文件头结构之类的了。
解析攻击
攻击角度来分是这样的:
直接解析(完全没防御或有一点简单的防御)
比如我们直接就可以上传一个扩展名是.php的文件,只需要简单地绕过客户端javascript 检测或者服务端MIME 类型检测就行了。
配合解析(有一定程度的防御)
我们可以理解为先代码注入到服务器上,上传一个带有一句话木马的图片或文件之类
让它待在某个位置,等待这一个解析的配合。(比如php 的文件包含解析,web 服务器的解析漏洞,.htaccess 解析等)
本地文件包含解析
主要是php 的本地文件包含(远程文件包含不属于上传攻击绕过范畴)
htaccess解析
就不用多说了,看看之前.htaccess 文件攻击的那个案例,用户自己定义如何去调用解析器解析文件就可以了。
web应用程序解析漏洞以及其原理
Apache 解析漏洞
解析: test.php.任意不属于黑名单且也不属于Apache解析白名单的名称
描述: 一个文件名为x1.x2.x3 的文件,Apache 会从x3 的位置往x1 的位置开始尝试解析,
如果x3 不属于Apache 能解析的扩展名,那么Apache会尝试去解析x2 的位置,这样一直往前尝试,直到遇到一个能解析的扩展名为止
IIS 解析漏洞
解析- test.asp/任意文件名|test.asp; 任意文件名| 任意文件名/任意文件名.php
描述- IIS6.0 在解析asp 格式的时候有两个解析漏洞,一个是如果目录名包含”.asp”字符串,那么这个目录下所有的文件都会按照asp 去解析,另一个是只要文件名中含有”.asp;”会优先按asp 来解析。
IIS7.0/7.5 是对php 解析时有一个类似于Nginx的解析漏洞,对任意文件名只要在URL后面追加上字符串”/任意文件名.php”就会按照php 的方式去解析。
Nginx 解析漏洞
解析- 任意文件名/任意文件名.php | 任意文件名%00.php
描述- 目前Nginx 主要有这两种漏洞,一个是对任意文件名,在后面添加/任意文件名.php
的解析漏洞,比如原本文件名是test.jpg,可以添加为test.jpg/x.php 进行解析攻击。还有一种是对低版本的Nginx 可以在任意文件名后面添加%00.php 进行解析攻击。
6.限制Web Server对于特定类型文件的行为
导致文件上传漏洞的根本原因在于服务把用户上传的本应是数据的内容当作了代码,一般来说,用户上传的内容都会被存储到特定的一个文件夹下,比如我们很多人习惯于放在 ./upload/ 下面要防止数据被当作代码执行,我们可以限制web server对于特定文件夹的行为。
大多数服务端软件都可以支持用户对于特定类型文件的行为的自定义,以Apache为例:
在默认情况下,对与 .php文件Apache会当作代码来执行,对于 html,css,js文件,则会直接由HTTP Response交给客户端程序对于一些资源文件,比如txt,doc,rar等等,则也会以文件下载的方式传送的客户端。我们希望用户上传的东西仅仅当作资源和数据而不能当作代码,因此可以使用服务器程序的接口来进行限制。
以Apache为例,我们可以利用 .htaccess 文件机制来对web server行为进行限制
在这里插一句,如果不是专门的文件下载目录,请务必关掉文件夹浏览的权限,以防止嗅探和可能的越权,也是使用.htaccess文件,在其中加上一句
1 | Options All -Indexes |
即可。
禁止脚本执行有多种方式可以实现,而且分别有不同的效果,我们分别来看一下
- 指定特定扩展名的文件的处理方式,原理是指定Response的Content-Type可以加上如下几行
1 | AddType text/plain .pl .py .php |
这种情况下,以上几种脚本文件会被当作纯文本来显示出来,你也可以换成其他的Content-Type
2. 如果要完全禁止特定扩展名的文件被访问,用下面的几行
1 | Options -ExecCGI |
在这种情况下,以上几种类型的文件被访问的时候,会返回403 Forbidden的错误
3. 也可以强制web服务器对于特定文件类型的处理,与第一条不同的是, 下面的方法直接强行让apache将文件识别为你指定的类型,而第一种是让浏览器
1 | <FilesMatch "\.(php|pl|py|jsp|asp|htm|shtml|sh|cgi)$"> |
看代码就可以很明白的知道,符合上面正则的全部被认为是纯文本,也可以继续往里面加入其他类型。
4. 只允许访问特定类型的文件
1 | <Files ^(*.jpeg|*.jpg|*.png|*.gif)> |
在一个上传图片的文件夹下面,就可以加上这段代码,使得该文件夹里面只有图片扩展名的文件才可以被访问,其他类型都是拒绝访问。
这又是一个白名单的处理方案。
永远记得,白名单是最有保障的安全措施。
三、反制
可以通过 move_uploaded_file 函数把自己写的.htaccess 文件上传,覆盖掉服务器上的文件,来定义文件类型和执行权限如果做到了这一点,将获得相当大的权限。