Web安全-文件上传漏洞
Webshell概念
Webshell是一种利用Web服务器的漏洞或弱点,通过远程上传恶意代码到服务器上(实质上是一种网页后门),并执行命令或控制服务器的一种攻击方式。在上传过后,该文件与网站服务器web目录下的正常网页文件混在一起,然后就可以通过该文件得到一个命令执行环境
攻击者可以通过Webshell获取服务器的高权限,进而进行非法操作,例如修改服务器文件、数据库操作、执行系统命令等。Webshell具有隐蔽性高、操作方便等特点,常被用于非法攻击、入侵行为或用于进行系统安全评估和渗透测试。通常为jsp,asp,php写成的脚本文件
注意:攻击者入侵服务器,使用webshell,无论传文件或者修改文件,必然会有一个文件包含webshell代码,我们有以下检测方式:
- 寻找静态特征,从文件代码入手检测
- webshell通常以HTTP交互,我们可以在HTTP的请求与响应中找寻痕迹
文件上传漏洞的原因
在普通的Web程序中,用户可以上传文件,而上传的文件可以被Web应用解析。假如未对用户上传文件进行检测或者检测不严格,一旦用户上传的恶意文件(甚至是Webshell)被服务器解析后(即文件上传与解析同时出现才能利用),将造成安全问题,即有两个条件:
- 用户可以绕过服务器检测上传恶意文件
- 恶意文件可以在一定条件下被解析
常见的上传漏洞
文件解析漏洞
这类漏洞通常是伴随着Web容器解析文件(文件已经在服务器上)而产生。常见的有:IIS,Nginx,Apache,Tomcat等
IIS解析漏洞
在IIS6.0版本中有两个常见漏洞:
- 当建立起
*.asa
,*.asp
的文件夹时,其中的任意格式文件都可以被解析为ASP脚本 - 当文件格式为
*.asp;1.jpg
时,该文件仍然会被当做ASP脚本被解析
Apache解析漏洞
在Apache 1x-2x的版本中存在一种文件解析机制:即在无法识别的扩展名文件被上传后,Apache会递归地,由后向前解析扩展名,直到遇到自己可识别的文件扩展名,如果都不能识别则会暴露出源代码(在Apache的安装目录中 "/conf/mime.types"
目录下存放着Apache的可识别文件类型目录)
PHP CGI解析漏洞
此漏洞与PHP的一个配置文件有关:cgi.fi: x_pathinfo
在某些版本中是默认开启的,在其处于开启状态下,当我们访问一个URL时加上x.txt/x.php
即 http://xxxxx.xxx/x.txt/x.php, 由于x.php文件不存在,则PHP会递归向前解析将 x.txt 文件解析为PHP脚本
文件上传漏洞
文件上传主要是未对用户上传文件进行检测或者检测不严格而产生(文件还未在服务器上),通常会有以下两种检测行为:
- 在客户端使用JavaScript进行文件校验,即在本地验证
- 服务端通过检测文件的Mime类型进行核验,检测出文件是否符合白名单或黑名单(部分会检测是否含恶意代码)
客户端检测
相较于服务端验证来说,客户端检测是非常好处理的,我们可以在客户端使用工具修改文件验证的JavaScript,也可以重新构造文件上传的HTML文档或者使用抓包软件截取报文来绕过
- 客户端使用工具修改文件验证的JavaScript:使用工具将报文中的表单中验证文件的对应事件删除即可
- 重新构造文件上传的HTML文档:通常情况下只需要删除form表单中的验证事件,将其他部分保留作为HTMl文档即可
- 使用抓包软件截取报文来绕过:我们可以将脚本修改成符合客户端检测的文件类型进行上传,然后进行抓包,将文件修改回原本的文件格式,这里需要注意Connect-Length的值,在修改后文件名可能会有字符长度的改变,所以为了防止可能发生的上传失败,我们需要将其修改成合适的长度
服务端检测
相较于客户端检测这种任何验证都是不安全的方式,服务端检测才能有效预防攻击者,通常有以下策略:
- 文件扩展名白名单检测:即只允许一种或几种文件类型允许被服务器接收
- 文件扩展名黑名单检测:处于黑名单中的文件类型不允许被服务器接收
- 文件重命名:即使文件上传成功,经过重命名后攻击者找到自己的脚本进行执行可能性下降
- 文件类型验证:基于MIME的验证等
绕过文件类型黑名单检测:
我们可以看出文件黑名单实质上是并不靠谱的,我们通常有以下绕过方式:
- 找到不在黑名单中的文件类型,并利用该类型的文件
- 针对于对字符大小写转换不敏感的平台,转换大小写绕过
- windows平台中文件扩展名后存在
.
或空格时,会自动去除,进行解析
绕过文件类型白名单检测:
白名单验证比黑名单验证更加安全,但是前文提到,文件上传和文件解析基本上是同时出现的,例如IIS与Apache的解析漏洞,我们都可以制作脚本文件修改后按漏洞构造以jpg结尾的扩展名(假使jpg在白名单中),一样可以绕过检测
绕过MIME文件验证(基于HTTP报文的验证):
MIME用来设定某种文件扩展名的打开方式,具有该文件扩展名的文件被访问时,浏览器会使用指定的应用程序来打开,这种方式也可以被用来检测文件合法性。常见的绕过手段是利用抓包软件修改报文中的Connect-Type类型来绕过验证,常见类型表如下:
类型 | 描述 | 典型示例 |
---|---|---|
text | 表明文件是普通文本,理论上是人类可读 | text/plain , text/html , text/css, text/javascript |
image | 表明是某种图像。不包括视频,但是动态图(比如动态 gif)也使用 image 类型 | image/gif , image/png , image/jpeg , image/bmp , image/webp , image/x-icon , image/vnd.microsoft.icon |
audio | 表明是某种音频文件 | audio/midi , audio/mpeg, audio/webm, audio/ogg, audio/wav |
video | 表明是某种视频文件 | video/webm , video/ogg |
application | 表明是某种二进制数据 | application/octet-stream , application/pkcs12 , application/vnd.mspowerpoint , application/xhtml+xml , application/xml , application/pdf |
转载自:MIME 类型 - HTTP | MDN (mozilla.org)
其他情况
目录验证利用:
在部分web应用中,如果文件上传到的目录存在则正常写入,不存在则创建目录,那么基于某些容器的解析特性,我们可以人为创造可能的漏洞环境,如IIS会解析*.asa
,*.asp
文件夹中的文件,那么我们可以想办法在不存在该目录的情况下建立一个*.asa
,*.asp
文件夹,后面再想办法利用该文件夹。
截断上传攻击:
截断上传攻击利用的是ASCII码中的NULL字符00,当一个字符串被解析时,我们通过这种在中间加入或替换00来加入null的操作会导致解析中断,即有效字符只有null之前的字符。举个例子,现在有一个文件上传检测,只允许*.png
的文件上传,那我们可以构造文件xxx.php .png
(注意中间有个空格),然后进行抓包,找到文件名对应的hex中的20(因为ASCII码表中空格是20)改成00,此时上传会上传成功,但是解析后由于null终止了,只剩下xxx.php
。
第二种方式则是在上传文件时直接将文件名构造为xxx.php%00.png
,截断后仍为xxx.php
文本编辑器漏洞
对于很多文本编辑器,在其目录下可能存在一些敏感目录,可以使用目录爆破这一手段获取敏感信息,有的编辑器甚至存在任意文件上传漏洞,这里由于编辑器众多,且版本较多,故不多赘述
MIME内容补充
后端获取MIME的方式
后端可以通过以下方式获取文件的MIME类型:
-
使用第三方库:许多编程语言都有相应的第三方库可以用来获取文件的MIME类型。这些库通常提供了函数或方法,通过传入文件路径或文件流来获取MIME类型。你可以搜索并选择适合你所使用的编程语言的库进行使用。
-
根据文件扩展名:大多数文件的扩展名与对应的MIME类型是有关联的。你可以创建一个字典或映射表,将文件扩展名与对应的MIME类型进行关联。当需要获取文件的MIME类型时,根据文件的扩展名查找对应的MIME类型即可。注意,这种方法可能会有一些特例和差异,所以最好使用专门的库来获取MIME类型。
-
使用系统命令:某些操作系统提供了命令行工具或命令,可以根据文件的扩展名或文件内容获取其MIME类型。你可以在后端代码中调用相应的系统命令来获取文件的MIME类型。
注意:获取文件的MIME类型并不能保证返回的结果是完全准确的,因为有些文件可能并没有明确的MIME类型或扩展名。所以在实际使用时,最好进行一些额外的验证和处理来确保文件的类型和安全性。
不依赖HTTP报文的情况
一般情况下,后端获取文件的MIME类型需要通过HTTP报文中的"Content-Type"字段来获取,因为该字段是由客户端在发送请求时设置的,如果后端不依赖HTTP报文,可以尝试其他方式获取文件的MIME类型。例如:
-
使用文件的扩展名:可以根据文件的扩展名来推测其MIME类型。在没有HTTP报文的情况下,可以使用文件系统相关的API(如Java的java.nio.file.Files类)或者操作系统的相关命令来获取文件扩展名,并根据扩展名来获取MIME类型。需要注意的是,这种方式只能推测MIME类型,不一定准确。
-
通过文件内容:有些文件格式的内容是有固定标识的,可以根据这些标识来判断文件的类型。例如,通过读取文件的二进制数据,根据特定的文件格式标识来确定其MIME类型。这种方式需要实现一些文件格式的解析逻辑,相对复杂并且不一定准确。
注意:上述方法可能无法准确地获取文件的MIME类型,特别是在文件格式多样且变化频繁的情况下。
漏洞的修复预防
- 建议使用白名单验证机制,白名单之外可终止该程序
- 严格过滤目录,防止人为构造目录
- 建议使用文件重命名操作,降低即使上传成功后被攻击者利用的可能
- 建立临时目录机制,严格限制文件的行为