文件上传漏洞详细解析
参考文章
一、漏洞介绍
文件上传漏洞是web安全中经常用到的一种漏洞形式。是对数据与代码分离原则的一种攻击。上传漏洞顾名思义,就是攻击者上传了一个可执行文件如木马,病毒,恶意脚本,WebShell等到服务器执行,并最终获得网站控制权限的高危漏洞。
二、漏洞原理
程序员在开发任意文件上传功能时,并未考虑文件格式后缀的合法性校验或者是否只在前端通过js进行后缀检验。这时攻击者可以上传一个与网站脚本语言相对应的恶意代码动态脚本,例如(jsp、asp、php、aspx文件后缀)到服务器上,从而访问这些恶意脚本中包含的恶意代码,进行动态解析最终达到执行恶意代码的效果,进一步影响服务器安全。
三、漏洞危害
- 上传漏洞与SQL注入或 XSS相比 , 其风险更大
- 上传的文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行。
- 上传的文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为。
- 上传的文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行。
- 上传的文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。
- 攻击者可以直接上传一个webshell到服务器上 完全控制系统或致使系统瘫痪。
四、利用前提
- 应有文件上传功能
- 对上传文件类型检测有漏洞
- 或检测文件类型的逻辑有漏洞(如,先保存文件,在检测文件类型)
五、利用流程
一般来说文件上传过程中检测部分由客户端javascript检测、服务端Content-Type类型检测、服务端path参数检测、服务端文件扩展名检测、服务端内容检测组成。但这些检测并不完善,且都有绕过方法。
1、判断上传漏洞点
多见于头像上传处
2、获得文件上传的url
使用mentra的firebug查找元素,或F12
3、测试防御类型
1.前端js检测
绕过方法:
禁用javasrcipt即可
2.后端检测检测文件类型
a.检测content-type
检测原理:
后端获取http请求包的Content-Type参数,判断上传文件类型
绕过方法:
抓包将content-type改为允许上传类型格式,即可成功上传
b.检测文件头判断文件类型
检测原理:
使用getimagesize()函数来获取文件的MIME类型,此时检测的不是数据包中的content-type,而是图片的文件头,常见的图片文件头如下:
gif(GIF89a) : 47 49 46 38 39 61
jpg、jpeg : FF D8 FF
png : 89 50 4E 47 0D 0A
绕过方法:
当上传php文件时,可以使用winhex、010editor等十六进制处理工具,在数据最前面添加图片的文件头,从而绕过检测
3.后端检测文件拓展名
a.黑名单检测
检测原理:
使用扩展名黑名单来限制上传文件类型
绕过方法:
1)使用一些特殊扩展名来绕过
php可以用php3、php4、php5代替
2)大小写混淆绕过
3)在文件名加.
(空格,点,空格),利用windows特性绕过
4)在文件名加::$data
绕过
b.白名单检测
检测原理:
要求只能是特定扩展名的文件才能上传
绕过方法:
使用%00截断文件名来上传,(注意:GET型可以对%00自动解码,但POST型不能,需要在二进制中修改)
如果目标还存在文件包含漏洞,那么就可以上传图片马再文件包含来拿shell
4.后端检测文件内容
a.文件内容替换
检测原理:
在后端处理上传的文件时,会将将文件中的敏感字符替换掉。
参考代码
<?php
$path = "./uploads";
$content = file_get_contents($_FILES['myfile']['tmp_name']);
$content = str_replace('?', '!', $content);
$file = $path . '/' . $_FILES['myfile']['name'];
if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
file_put_contents($file, $content);
echo 'Success!<br>';
} else {
echo 'Error!<br>';
}
?>
绕过方法:
根据实际过滤的字符来判断,(一般不会限制所有敏感字符,因为还要兼顾图片上传)
b.图片二次渲染
检测原理:
后端调用了php的GD库,提取了文件中的图片数据,然后再重新渲染,这样图片中插入的恶意代码就会被过滤掉了
绕过方法:
比较过滤前后文件内容,一般不会全部过滤。
比较使用php-gd转换之前和之后的gif图像,并搜索它们之间的任何相似性,因此,如果我在原始文件中找到相似的部分,则在使用php-gd转换后也保留了该部分然后我可以在那部分注入我的PHP代码并获得RCE
5.条件竞争
该漏洞形成逻辑:
网站允许上传文件,然后检查上传文件是否包含webshell、是否是指定的文件类型。如果不是,那么删除该文件。在删除之前访问上传的php文件,从而执行上传文件中的php代码。
绕过方法:
先进行文件上传,后进行判断与删除。利用时间差进行webshell上传。
竞争条件代码举例:
<?php
fputs(fopen('shell.php','w'),'<?php @eval($\_POST\["cmd"\])?>');
?>
判断是否删除
import requests
while true:
requests.get(”路径“)
六、漏洞修复
1、系统运行时
- 文件上传的目录设置为不可执行。只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响,因此这一点至关重要。
- 判断文件类型。在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文
件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。 - 使用随机数改写文件名和文件路径。文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。
- 单独设置文件服务器的域名。由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含Javascript的XSS利用等问题将得到解决。
- 使用安全设备防御。文件上传攻击的本质就是将恶意文件或者脚本上传到服务器,专业的安全设备防御此类漏洞主要是通过对漏洞的上传利用行为和恶意文件的上传过程进行检测。恶意文件千变万化,隐藏手法也不断推陈出新,对普通的系统管理员来说可以通过部署安全设备来帮助防御。
2、系统开发时
- 系统开发人员应有较强的安全意识,尤其是采用PHP语言开发系统。在系统开发阶段应充分考虑系统的安全性。
- 对文件上传漏洞来说,最好能在客户端和服务器端对用户上传的文件名和文件路径等项目分别进行严格的检查。客户端的检查虽然对技术较好的攻击者来说可以借助工具绕过,但是这也可以阻挡一些基本的试探。服务器端的检查最好使用白名单过滤的方法,这样能防止大小写等方式的绕过,同时还需对%00截断符进行检测,对HTTP包头的content-type也和上传文件的大小也需要进行检查。
3、系统维护时
- 系统上线后运维人员应有较强的安全意思,积极使用多个安全检测工具对系统进行安全扫描,及时发现潜在漏洞并修复。
- 定时查看系统日志,web服务器日志以发现入侵痕迹。定时关注系统所使用到的第三方插件的更新情况,如有新版本发布建议及时更新,如果第三方插件被爆有安全漏洞更应立即进行修补。
- 对于整个网站都是使用的开源代码或者使用网上的框架搭建的网站来说,尤其要注意漏洞的自查和软件版本及补丁的更新,上传功能非必选可以直接删除。除对系统自生的维护外,服务器应进行合理配置,非必选一般的目录都应去掉执行权限,上传目录可配置为只读。