文件上传漏洞
什么是文件上传漏洞
web服务器允许用户上传文件到其系统,但未对文件名、类型、内容、大小进行充分的验证;这意味着最基本的图片上传功能也可以用来上传危险文件,包括远程代码执行的脚本文件;后续的攻击通常是为了触发上传的文件。
影响
文件上传漏洞通产取决于两点:
网站未能正确验证文件的哪些方面,包括:文件的大小、类型、内容等
成功上传文件后会受到哪些限制
在最坏的情况下,文件类型没有正确验证,并且服务器配置允许某些类型的文件(.php和.jsp)作为代码执行;在这种情况下,攻击者可能会上传一个服务端代码文件,作为web shell使用,从而控制服务器。
如果是文件名未正确验证,攻击者可能只需要上传同名文件即可覆盖关键的文件。如果服务器还存在目录遍历漏洞,这就意味着攻击者甚至能够将文件上传到意想不到的位置。
如果无法确保文件大小在预期范围之内,还可能导致某种形式的拒绝服务(Dos)攻击,攻击者会借此填满可用磁盘空间。
文件上传漏洞如何产生
因为文件上传漏洞危害性非常的大,大部分网站基本都会对用户上传的文件做出限制,开发人员做出的这些验证要么存在固有缺陷,要么很容易被绕过。
例如开发人员可能会将危险的文件类型列入黑名单,但是在检查文件扩展名时未能考虑到解析差异;与其他的黑名单一样,也很容易忽略仍然危险的更模糊的文件类型。
在其他情况下,网站可能会通过验证属性来检查文件类型,攻击者可以使用burp proxy或repeater等工具来轻松改变这些属性。
web服务器如何处理静态文件的访问
当通过路径访问文件时会判断一下文件类型,分三种方式
如果文件是不可执行的,相是图像或静态html页面,则服务器可能只会在http响应中向客户端发送文件内容
如果文件是可执行的,例如php文件,并且服务器配置为能够执行该类型的文件,那么在运行脚本之前,服务器会根据http请求中的header和参数来分配变量。由此产生的输出结果会在http响应中发送给客户端
如果文件是可执行的,服务器未配置为能够执行该类型的文件,则通常会返回错误。但是在某些情况下,文件的内容仍可能以纯文本形式提供给客户端。这种错误配置有时会被利用来泄露源代码和其他错误信息。
利用不受限制的文件上传来部署web shell
web shell
web shell是一种恶意脚本,攻击者只需将http请求发送到正确的端点即可在远程web服务器上执行任意命令
最坏的情况就是网站允许你上传服务器端脚本(例如php、java、python文件),并将其配置为代码执行。如果能够成功上传web shell,那么就可以完全控制服务器,这意味着可以读取和写入任意文件、窃取敏感数据,甚至使用服务器对内部基础设施和网络外部的其他服务器进行攻击。例如,以下php单行代码可用于从服务器的文件系统读取任意文件:
上传之后,发送对此恶意文件的请求将在响应中返回目标文件的内容。
更为常见的为如下类型:
这个脚本能够通过查询参数传递任意系统命令
给参数command赋值为pwd,即可在系统内部执行pwd命令
利用文件上传验证漏洞
在正常情况下很少遇到对上传文件不做限制的,但就算是防御措施到位,也并不意味着是一定安全的,有时候仍然可以利用这些防护机制中的缺陷来获取用于远程代码执行的web shell。
在提交html表单时,浏览器通常会在post请求中附带所提供的数据,类型为application/x-www-form-url-encoded。这种类型对于发送简单的文本(像是姓名或地址)很合适,但是不适合发送大量的二进制数据,像是图像文件或pdf文档,在这种情况下,内容类型的首选就是multipart/form-data
这道题对上传的文件做出了限制,使用burpsuite抓包会发现文件类型为application/octet-stream
可以看到需要image/jpeg或image/png文件类型
因此直接将文件类型改掉,重新发送即可
防止在用户可访问的目录下执行文件
我们通过上传文件可以发现,文件储存在/files/avatars中,按照正常思路上传php文件并且执行。但是得到结果为php文件中的代码,说明当前文件中可能禁止用户执行文件
使用burpsuite对上传文件的请求拦截
根据题目的提示尝试使用目录遍历../看能不能上传到上一级的文件
改完后上传,看响应还是传到/files/avatars的目录下,说明服务器可能对../有过滤,可以尝试使用url编码%2e%2e%2f
成功绕过检测
接下来直接访问/files/try.php即可
危险文件类型黑名单不足
防止用户上传恶意脚本的一个比较常用的方法是将.php等潜在危险文件扩展名列入黑名单。但是这种做法本质上是有缺陷的,因为很难明确的阻止所有执行代码的文件扩展名。仍然可以使用一些鲜为人知的文件扩展名(.php5、.shtml等)来进行绕过。
覆盖服务器配置
服务器通常不会执行文件,除非经过配置。例如,在Apache服务器执行客户端请求的php文件之前,开发人员可能需要在**/etc/apache2/apache2.conf**文件中配置如下指令:
许多服务器还允许开发人员在个别目录中创建特殊配置文件,用于添加一个或多个全局配置。例如,Apache服务器会从名为.htaccess的文件加载特定目录的配置
同样,开发人员可以使用web.config文件对IIS服务器进行特定目录配置,可能包括以下指令,这些指令允许向用户提供json文件:
web服务器会使用这类配置文件,但通常不允许使用http请求访问它们。不过,偶尔会发现服务器无法阻止我们上传自己的恶意配置文件。在这种情况下,即使需要的文件扩展名被列入了黑名单,也可以欺骗服务器将任意的自定义文件扩展名映射到可执行的MIME类型。
这道题就是将php后缀的文件设置为黑名单,此时可以尝试覆盖一下服务器的配置,先上传一张正常的图片,使用burp查看上传的请求,将文件名改为.htaccess,将Content-Type内容改为text/plain,将文件内容改为AddType application/x-httpd-php .php5
这里AddType application/x-httpd-php .php5的作用是将.php5后缀的文件映射为以php的方式来执行
如此就可以将准备好的web shell文件上传了
找到文件的所在路径,访问即可运行web shell
伪装文件扩展名
即使是最详细的黑名单,也有可能被经典的伪装技术绕过。假设验证代码对大小写敏感,无法识别try.pHp实际上就是.php文件。如果随后将文件扩展名映射到MIME类型的代码对大小写不敏感,这种差异就会使php文件偷偷通过验证,最终被服务器执行。
可以使用以下技术来获得类似的结果:
提供多种扩展名,根据解析文件名所使用的算法,以下文件可能被解释为php文件或jpg图像:try.php.jpg
添加尾部字符,某些组件会删除或忽略尾部的空格、点等类似字符:try.php.jpg.
尝试使用url编码(或双url编码)。如果在验证文件扩展名时该值未解码,但稍后在服务器端解码,这样也可以上传原本会被阻止的恶意文件:try%2Ephp
在文件扩展名前添加分号或url编码的空字节字符。如果验证是用php或java等高级语言编写的,但服务器使用c/c++等低级函数处理文件,这可能会导致文件名末尾的处理不一致:try.asp;.jpg或try.asp%00.jpg
尝试使用多字节unicode字符,这些字符可能会在unicode转换或规范化后被转换为空字节和点。如果文件名解析为utf-8字符串,如:xC0 x2E,xC4 xAE 或 xC0 xAE等序列可能会被转换为x2E。但在路径使用前会被转换为ASCII字符
其他的一些防御措施包括删除或替换危险的扩展名,以防止文件被执行。如果这种转换不是递归应用的,那我们可以将字符串设置为删除危险扩展名后任然会留下一个有效的扩展名。如下,即使将.php删除掉,文件扩展名依旧是有效的:
try.p.phphp
这只是伪装文件扩展名的众多方法中的一种
这道题是对文件后缀有过滤,按照上述的方法一个一个挨着试过去即可,大小写敏感、添加扩展名、添加尾部字符、使用(双)url编码、文件扩展名前添加分号或空字节符、多字节unicode字符等。方法虽然多,但一定要一个个试过去,在自己做这道题的过程中,只剩下扩展名前添加空字节符这一种情况没试,然而突破口正好就是空字节符,在真实环境中就正好错过了一个漏洞。以此作为警示,万事需毕其功,不可心存侥幸。
文件内容验证存在缺陷
更安全的服务器会尝试验证文件内容是否与预期相符,而不是只信任请求中指定的Content-Type。在图像上传功能中,服务器可能会尝试验证图像的某些固有属性,比如:尺寸。例如,如果尝试上传一个php脚本,它根本不会有任何尺寸。因此,服务器会推断它不可能是图像,并拒绝上传。
同样,某些文件类型的页眉或页脚可能是包含特定的字节序列。这些可以像指纹或签名一样用来确定文件内容是否符合预期类型。例如,jpeg文件总是以FF D8 FF开头。
这是验证文件类型的一种更稳健的方法,但即便如此也不是万无一失。使用ExifTool等特殊工具,可以轻而易举地创建一个在元数据中包含恶意代码的多格式jpeg文件。
exiftool工具使用格式如下:
有些时候服务器可能会检查文件中是否含有关键字php,来过滤文件中是否含有php脚本。这里还有一种超短shell的方法,只需将php代码替换为:
这里利用的是PHP命令执行的特性。`号内会被当做命令执行。传参如下:
访问即可在START和END之间获得命令运行结果
利用文件上传竞争条件
现在的框架对文件上传的防御力要更强,它们一般不会直接将文件上传到文件系统上的目标位置。通常都会采取一些防御措施,比如先上传到一个临时的沙盒目录,并随机化名称来避免覆盖现有文件。然后再对临时文件进行验证,只有在认为安全后才将文件传输到目的地。
尽管如此,开发人员有时会独立于任何框架实现自己的文件上传处理。做好这一点不仅相当复杂,还可能引入危险的竞争条件,使攻击者能够完全绕过最强大的验证。
例如,有些网站会将文件直接上传到主文件系统,没有通过验证,就会再次删除。这种行为在依赖反病毒软件等检查恶意软件的网站中很常见。这可能只需要几毫秒,但文件存在于服务器上的段时间内,攻击者仍有可能执行该文件。
这些漏洞往往非常隐蔽,因此很难在黑盒测试中发现,除非能找到泄露相关代码的方法。
这里使用比较传统的方法,使用intruder进行post快速爆破,在这个过程中使用reapeter发一个get请求,即可调用暂存的php文件
基于url的文件上传中的竞争条件
在允许提供url上传文件的函数中,也会出现类似的竞争条件。在这种情况下,服务器必须通过互联网获取文件并创建本地副本,然后才能执行任何验证。
由于文件是使用HTTP加载的,因此开发人员无法使用框架的内置机制来安全地验证文件。相反,它们可能会手动创建自己的流程来临时储存和验证文件,但这样可能不太安全。
例如,如果文件被加载到一个名称随机的临时目录中,理论上攻击者就不可能利用任何竞争条件。如果攻击者不知道目录名,就无法请求文件来触发文件的执行。另一方面,如果是使用伪随机函数(如php的uniqid())生成随机目录名,就有可能被暴力破解。
为了让这种攻击更容易得手,可以尝试延长处理文件的时间,从而延长暴力破解目录名的时间窗口。一种方法是上传较大的文件,如果文件是分块处理的,可以通过创建一个恶意文件来利用这一点,在文件开头添加有效payload,然后添加大量任意填充字节。
不执行远程代码来利用文件上传漏洞
在上面提到的练习和实例中,我们可以上传脚本到服务器来远程执行代码(rce)。这是文件上传功能不安全造成的最严重的后果。
上传恶意客户端脚本
尽管我们可能无法在服务器上执行脚本,但依然可以上传脚本进行客户端攻击。例如,如果可以上传HTML文件或SVG图像,就有可能使用标签来创建储存有XSS的payload。
如果上传的文件出现在其他用户访问的页面上,他们的浏览器在尝试呈现页面时就会执行脚本。注意:由于同源策略的限制,这类攻击只有在上传的文件与上传文件的源相同时,才会起作用。
利用解析上传文件的漏洞
如果上传的文件储存和提供服务都很安全,最后的办法就是尝试利用解析或处理不同文件格式的特定漏洞。例如,当我们知道服务器会解析基于XML的文件,那么.doc或.xls文件就可能是XXE注入攻击的潜在媒介
使用PUT上传文件
值得注意的是,某些web服务器可能配置为支持PUT请求。如果没有适当的防御措施,即使网络接口没有上传功能,也可以通过这种方式上传恶意文件。
如:
tips:可以尝试向不同的端点发送options请求,以测试是否有任何端点支持put方法
如何防范文件上传漏洞
允许用户上传文件是很常见的事,只要采取正确的防御措施,就不会有什么危险。一般来讲,保护自己网站免受这些漏洞攻击的最有效方法是实施以下所有做法:
通过白名单来检查文件扩展名,而不是通过黑名单
确保文件名不包含任何可能被解释为目录或遍历序列(../)的字符串
重命名上传的文件,以避免现有文件被覆盖
在完全验证文件之前,请勿将文件上传到服务器的永久文件系统
Last updated