重要声明
该培训中提及的技术只适用于合法CTF比赛和有合法授权的渗透测试,请勿用于其他非法用途,如用作其他非法用途与本文作者无关
我们今天来了解一下任意文件上传漏洞
什么是文件上传
文件上传
文件上传包括了上传头像,上传相册,上传附件,添加新闻图片,自定义主题背景,新闻投稿等等,一个很简单的栗子就是微信或者QQ的头像上传功能,或者上传到百度云这种
漏洞产生原因
那漏洞的产生原因呢,分为两种
1. 代码层
开发者由于对安全意识不足,或者编写代码时对上传文件的合法校验存在缺陷,导致上传漏洞的产生
2. 应用层
Web容器漏洞、cgi、配置不当等等
漏洞的利用
我们现在说说怎么利用漏洞
一. 使用了JavaScript校验的上传点
当我们遇到一个网站的上传拦截只是使用了JavaScript来校验的时候,下一步我们要做的就是判断绕过JavaScript上传是否可行
1. 由于是JavaScript前端校验,判断上传非法文件那个提示时,有无http包发出
2. 查看HTML代码中是否有相关JavaScript代码
那说说如何利用
利用的话,我们可以直接暴力一点,删除相关的JavaScript代码,或者修改我们的上传文件的后缀为允许上传的文件类型
二. 只使用了黑名单校验的上传点
由于上传文件的合法性校验使用的是黑名单的方式判断上传文件后缀,因为有些黑名单不全,就存在被攻击者绕过导致的上传漏洞
要判断一个黑名单是否可以绕过,我们可以用试错法,如
上传一个现实中不存在的后缀名文件(file.hatsune),观察服务器的返回情况
如果服务器上传成功,说明这个服务器用的就是黑名单
那还是说说我们如何绕过
绕过也很简单,我们可以使用如下的变换手段:
1. 变换为等价的文件后缀名
Asp->Asa or cer or cdx
php->php3 or php4 or php5
jsp->jspx
etc.
2. 大小写相互转换
如:
asp->asP
php->pHp
etc.
3. 利用一些系统的内置规定
比如
test.test.
or
test.test_(Windows文件名特性)
最后一种方法呢就是比较高级的了
4. 0x00截断
这个绕过方法呢是利用一些php函数的解析文件后缀名的规律
比如我们这里有个这样的代码
name=getname(request);
type=gettype(name);
If(type==jpg){
SaveFileToPath(UploadPath.name, name);
}
在这里,我们用gettype()函数<从后往前>判断后缀名
假设我们上传一个php文件叫test.php,在上传的时候用BurpSuite截包了,将文件名改为了这样
test.php .jpg
其中test.php与.jpg之间是一个空格
然后我们用BurpSuite自带的Hex格式打开(这里我随便截了一个包演示一下)
我们将这个文件改为
然后我们用Hex格式打开(我们注意一点,这里的Hex不是指ASCII编码,而是URL编码)
我们找到20的地方(%20是空格的URL编码)
把他修改成为00
然后这时候我们就完成了这个0x00截断,服务器因为存在00,所以就会忽略后面的内容,于是我们的文件就绕过了校验上传上去了
三. 只使用了MIME类型检测文件的上传点
什么是MIME,这里有个解释
MIME(Multipurpose Internet Mail Extensions)是描述消息内容类型的因特网标准
MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据
然后这里有个按照内容类型排列的MIME类型列表
类型/子类型 | 扩展名 |
---|---|
application/envoy | evy |
application/fractals | fif |
application/futuresplash | spl |
application/hta | hta |
application/internet-property-stream | acx |
application/mac-binhex40 | hqx |
application/msword | doc |
application/msword | dot |
比如这里有一个代码是这样的
if(($_FILES["file"]["type"] == "image/jpeg")){
do_something();
}
else{
echo "Only jpg file can upload";
}
上面这个代码就是使用了MIME的类型检测,那我们怎么绕过这个上传点呢?
我们可以这样
在上传比如一个php文件的时候,我们截包,将上传流量里面的
...
Content-Type: text/php
...
修改为
...
Content-Type: image/jpeg
...
四. 存在解析漏洞的上传点
这个利用就比较暴力了,如果是你自己发现的某个Web中间件存在这种漏洞,那基本都是0day类型的
这个漏洞的成因也很多,基本就是,Web中间件的漏洞或者Web服务器与cgi处理的差异,运气最好的就是运帷人员配置不当
那我们用几个历史上真实发生过的栗子来说说利用方法吧
很著名的有这么几个
1. IIS6解析漏洞一
我们可以构造上传文件名为这样的
webshell.asp;test.jpg
因为这时候IIS只会解析到后面的jpg文件类型而没有前面的asp
所以就允许你上传了,但是我们上传的文件里面其实还包含了一个webshell.asp
之后我们的webshell.asp就绕过了上传限制上传到了服务器上了,且这个webshell.asp不会被重命名
(是不是突然有点羡慕千禧年的黑客们,那时候人们安全意识也很弱,加上计算机基础也不是很好,网站基本都是千疮百孔的啊哈哈哈,这种漏洞现在基本不会见到了)
2. IIS6解析漏洞二
比如我们构造上传文件名为
webshell.asp/test.jpg
这个解析漏洞是呢在服务器上可以建立任意名称的文件夹,也就是我们前面的webshell.asp那是一个<文件夹>的名字
然后同时也可以在该文件夹下上传其他文件或创建其他文件夹
3. Apache解析漏洞
这个漏洞和上面的也差不多
这个漏洞的成因和我们上期讲的逻辑漏洞是一样的
首先我们构造一个文件名为
webshell.php.jpg
Apache呢会先从后往前尝试解析,然后解析到了一个jpg
因为这个jpg是Apache默认不解析的文件名,所以Apache会跳过这个jpg继续往前解析,直到解析到了我们的php
这个我就懒得复现截图了,我们就大概说一下利用方法
比如我们一个php文件叫webshell.php
我们点击上传,然后BurpSuite截包,将文件名改为
webshell.php.jpg
OK,上传成功,之后我们在服务器执行
http://x.x.x.x/webshell.php.jpg
这里是假设我们的上传路径就是网站的根目录,如果不是就自行改成其他目录
之后我们的php代码就会被Apache执行了
这个解析漏洞的一个好处就是文件上传后不会对文件名进行重命名
漏洞版本包含
apache 2.0.x <= 2.0.59
apache 2.2.x <= 2.2.17
apache 2.2.2 <= 2.2.8
4. Nginx解析漏洞
这个漏洞呢是Nginx本身代码编写时候就存在的,Nginx与php-cgi处理方式存在差异造成了这个漏洞
我们可以这样
首先在本地有个webshell.php文件
之后我们上传,然后将这个上传的php文件名截包,并改为
webshell.jpg%00.php
绕过上传限制
之后
当服务器中设置了cgi.fix_pathinfo = 1的时候
php就会以'/'为分割符从<最后一个文件>开始<向前>找<存在的文件>去执行
然后我们执行(还是假设上传目录在网站根目录)
http://x.x.x.x/webshell.jpg/abc.php
我们上面已经大概说了一下原理
php会以'/'为分隔符取找存在的文件取执行
这里abc.php是我乱写的,故意让服务器找不到这个文件,肯定是不存在的
之后Nginx找不到这个文件,就会去试着去前面执行我们的webshell.jpg
然后我们的的webshell里面写的php代码就被Nginx执行了
漏洞包含的版本
nginx 0.5.*
nginx 0.6.*
nginx 0.7 <= 0.7.65
nginx 0.8 <= 0.8.37
祝大家端午节快乐~