文件上传漏洞
简介
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令(webshell)的能力。文件上传在互联网应用中是很正常的需求,问题不是出现在需求上,而是在文件上传服务器后服务器如何处理、解析该文件,若服务器处理不恰当,则可能会造成比较严重的问题。
文件上传后导致的常见安全问题一般有:
- 上传文件是 Web 脚本语言,服务器的 Web 容器解释并执行了用户上传的脚本,导致代码执行;
- 上传文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行;
- 上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。
经典例子
Apache 文件解析问题
在 Apache 1.x、部分 2.x 中,对文件名的解析存在以下特性:Apache 对于文件名的解析是从后往前解析的,直到遇见一个 Apache 认识的文件类型为止。比如:
1 | 文件: PhpShell.php.rar.rar.rar // 上传至指定服务器根目录 |
因为 Apache 并不认识 rar 这个文件类型,所以会一直遍历到 php 后缀,然后认为这是一个 PHP 类型的文件。也就是说,当访问该资源时候,Apache 将会将其当成 php 文件执行:
1 | http://127.0.0.1/PhpShell.php.rar.rar.rar |
运行结果:
那么如何知道 Apache 认识哪些文件类型?通过 Apache 根目录下 conf 文件夹的 mime.types 文件便可以知道。
针对这种情况,在 apache conf/httpd.conf 文件中增加如下配置来禁止.php. .php3. .php4.
等等这样的文件执行:
1 | <Files ~ ".+.ph(p[3457]?|t|tml)."> |
IIS 文件解析问题
IIS 6 存在这样一个漏洞:当文件名为 test.asp;xx.jpg 时,IIS 将会将其当成 test.asp 文件进行解析,;
及其后面的 xx.jpg 被忽略,简单地说,文件名被截断了。
当服务器中存在 test.asp;123.jpg 的图片文件时,客户端通过如下 url 查看:
1 | http://127.0.0.1/test.asp;123.jpg |
正常情况下应该是返回一张图片,但由于 IIS 6 上面的这个特性(微软官方不承认这是个 bug),;
及其后面的 123.jpg 被截去了,导致 IIS 6 直接将其当作.asp 文件来解析,从而造成了安全问题。比如:
1 | 文件: now.asp;123.jpg |
发起请求访问该文件:
1 | http://127.0.0.1:8181/now.asp;123.jpg |
返回结果:
除了上面这个漏洞外,IIS 6 还有个更加严重的问题。当服务器中建立如*.asa、*.asp 的文件夹时,其下的所有文件都会被当作 asp 脚本执行。如下:
1 | 文件: parsing.asp/now.jpg |
发起请求访问该文件:
1 | http://127.0.0.1:8181/parsing.asp/now.jpg |
返回结果:
不过,上述两个漏洞需要该文件确实存在于服务器本地存储中,若只是映射出来的 URL,是无法触发 bug 的。
WebDav
WebDav 大大扩展了 HTTP 协议中 GET、POST、HEAD 等功能,它所包含的 PUT 方法,允许用户上传文件到指定的路径下。但除了 PUT,它还支持 MOVE、COPY 等方法对服务器文件进行修改,这样就产生了如下的文本漏洞:通过 PUT 上传文件至指定路径,在结合 MOVE/COPY 方法修改该文件为脚本文件。例如:
1 | 文件名: 123.jpg // 通过PUT方法上传 |
然后再通过http:127.0.0.1:8181/123.asp
访问,成功获取 webshell 执行脚本。此外,DELETE 方法的开启也可能导致文件被恶意删除,所以使用 WebDav 时需要多加注意。
PHP CGI 解析漏洞
2010 年 5 月,国内的安全组织 80sec 发布了一个 Nginx 的漏洞,指出在 Nginx 配置 fastcgi 使用 PHP 时,会存在文件类型解析问题:当请求 url 为http://www.test.com/1.jpg/1.php
且 1.php 不存在但 1.jpg 存在时,会把 1.jpg 当作 php 类型文件进行解析执行。这就意味着攻击者可以上传合法的“图片木马”,然后在访问该”图片木马“时在 url 末尾加上“/*.php”),即可获得 webshell。
后来经人们深入研究发现,产生漏洞的根本原因并不是 Nginx,而是因为某些版本的 PHP CGI。在 PHP 的配置文件中有一个关键选项:cig.fi: x_pathinfo,这个选项在某些版本中是默认开启的,在开启时访问 URL,比如http://www.test.com/1.jpg/1.php
,1.php 是不存在的文件,PHP 将会往前递归解析,于是造成了解析漏洞。这个往前递归的功能原本是想解决http://www.test.com/1.php/test
这种 URL,能够正确地解析到 1.php 上。所以,在其他使用了该版本 PHP CGI 的 Web 容器中也存在上述漏洞,例如 IIS 7、IIS 7.5。
有人向 PHP 官方提供了第三方补丁试想修补这个 bug,但是官方不认为这是一个 bug,拒绝修改。官方给出的建议是将上述选项关闭,但是可想而知,对于不知情者仍然存在遭受损失的风险。
绕过检查的 N 种手段
常见的防御手段是进行文件类型检查,但由于疏忽或者检查不到位,容易被攻击者绕过。
单独地前端限制文件类型
1 | function check() { |
仅通过表单上传前进行文件格式检查是否是图片,这显现是不可靠的。对于专业的黑客来说有 N 种手法绕过。
- 正常上传图片格式,使用 BurpSuite 或其他工具截取数据包,并将数据包中文件扩展名更改回原来的,达到绕过的目的。例如正常上传 PHP 图片木马 1.jpg,截取数据包后将其改正为 1.php,然后通过 url 正常访问。
- 直接通过开发者工具移除该事件函数。
- 浏览器直接设置禁用 JavaScript。
这里使用的是白名单策略,相对来说并没有太多缺陷,但如果是使用黑名单策略问题就大了:通过.htaccess 规则文件绕过、通过文件后缀大小写绕过等等。
解释:.htaccess 文件(或者”分布式配置文件”),全称是 Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。概述来说,.htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 htaccess 文件,可以帮我们实现:网页 301 重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能,若安全检查通过黑名单策略进行,遗漏了此类型的文件时,攻击者就可以利用.htaccess 文件改变 web 容器的配置,制造破坏。
单独地后端限制文件类型
这里只讨论白名单策略安全检查。
1 | $postfix = end(explode('.', $_POST['filename'])); |
上面这段 PHP 表示只允许接收保存 jpg、png、gif 三种图片格式,在 php<5.3.4 的版本中,有这样一个 bug:在部分字符串处理函数中,0x00 被认为是终止符。假设上述代码拦截的请求中,filename 为 1.jpg%00.php,在 explode 中则可能会被当作 1.jpg 处理,然后得到的后缀就是 jpg 了,成功绕过检查,但存储的确实是 php 格式文件。
防御手段
文件上传的目录设置为不可执行
只要 Web 容器无法解析该目录下的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响,因此此点至关重要。在实际应用中,很多大型网站的上传应用,文件上传后会放到独立的存储上,做静态文件处理,一方面方便使用缓存加速,降低性能损耗;另一方面也杜绝了脚本执行的可能。
windows 可通过右键->属性打开下面面板进行修改文件夹权限:
linux 则可以通过命令进行修改:
1 | chmod 777 /use/www/WebSecurity |
判断文件类型
判断文件类型也能在一定程度上避免上传漏洞,前后端双重校验效果最佳。
前端检验:
1 | function check() { |
后端检验(PHP):
1 | $postfix = end(explode('.', $_POST['filename'])); |
前端在表单上传之前检查文件类型,若不符合则不允许提交。单靠表单检查类型是不安全的,因为前端的代码时完全暴露并且允许在开发者工具中进行修改,比如直接去掉这个事件绑定,对于专业人员来说完全起不了作用,所以需要结合后台进行类型限制。无论是后台还是前端,统一使用白名单策略,指定允许通过的文件类型,不在白名单外的全都视为非法类型不允许通过,相对黑名单策略更加安全,因为黑名单总有遗漏的文件类型。
此外,还可以检查 HTTP Header 中的 Content-Type,HTTP 协议规定了上传资源的时候在 Header 中加上一项文件的 MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型。不过这仍然是不安全的,因为 HTTP header 可以被发出者或者中间人任意的修改,不过聊胜于无。
使用随机数改写文件名和文件路径
文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用使用随机数改写了文件名和路径,将极大地增加攻击的成本。与此同时,像 shell.php.rar.rar 这种文件,将因为文件名被改写而无法成功实施攻击。
单独设置文件服务器的域名
由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传包含 JavaScript 的 XSS 利用等问题将得到解决。但能否如此设置,还需要看具体的业务环境。
总结
文件上传是一个常见的业务需求,但因其与服务器直接交互,所带来的安全问题也是相对严重的,也是黑客的重点关注对象,为此需要安全人员做足充分的安全检查,才能保证服务器安全。