⽂件上传漏洞
⽂件上传漏洞
在本节中,您将了解如何将简单的⽂件上传函数⽤作许多⾼严重性攻击的强⼤载体。我们将向您展⽰如何绕过常见的防御机制以上传 Web Shell,从⽽使您能够完全控制易受攻击的 Web 服务器。鉴于⽂件上传功能的常见程度,知道如何正确测试它们是必不可少的知识。
实验室
如果您已经熟悉⽂件上传漏洞背后的基本概念并且只想开始练习,您可以从下⾯的链接访问本主题中的所有实验室。
什么是⽂件上传漏洞?
⽂件上传漏洞是指 Web 服务器允许⽤户在没有充分验证⽂件名称、类型、内容或⼤⼩等内容的情况下将⽂件上传到其⽂件系统。未能正确执⾏这些限制可能意味着即使是基本的图像上传功能也可⽤于上传任意且具有潜在危险的⽂件。这甚⾄可以包括启⽤远程代码执⾏的服务器端脚本⽂件。
在某些情况下,上传⽂件的⾏为本⾝就⾜以造成损害。其他攻击可能涉及对⽂件的后续 HTTP 请求,通常是为了触发服务器执⾏该⽂件。⽂件上传漏洞有什么影响?
⽂件上传漏洞的影响⼀般取决于两个关键因素:
⽹站未能正确验证⽂件的哪个⽅⾯,⽆论是其⼤⼩、类型、内容等。
⽂件成功上传后会受到哪些限制。
在最坏的情况下,⽂件的类型没有得到正确验证,服务器配置允许某些类型的⽂件(例如.php和.jsp)作为代码执⾏。在这种情况下,攻击者可能会上传⼀个充当 Web shell 的服务器端代码⽂件,从⽽有效地授予他们对服务器的完全控制权。
如果⽂件名没有得到正确验证,这可能允许攻击者通过上传同名⽂件来覆盖关键⽂件。如果服务器也容易受到的攻击,这可能意味着攻击者甚⾄可以将⽂件上传到意外位置。
未能确保⽂件⼤⼩在预期阈值范围内还可能导致某种形式的拒绝服务 (DoS) 攻击,攻击者借此填满可⽤的磁盘空间。
⽂件上传漏洞是如何产⽣的?
鉴于相当明显的危险,野外⽹站很少对允许⽤户上传哪些⽂件没有任何限制。更常见的是,开发⼈员实施他们认为具有内在缺陷或可以轻松绕过的强⼤验证。
例如,他们可能会尝试将危险⽂件类型列⼊⿊名单,但在检查⽂件扩展名时未能考虑解析差异。与任何⿊名单⼀样,也很容易意外忽略可能仍然危险的更晦涩的⽂件类型。
在其他情况下,⽹站可能会尝试通过验证攻击者可以使⽤ Burp Proxy 或 Repeater 等⼯具轻松操纵的属性来检查⽂件类型。
最终,即使是强⼤的验证措施也可能在构成⽹站的主机和⽬录⽹络中不⼀致地应⽤,从⽽导致可以利⽤的差异。
在本主题的后⾯,我们将教您如利⽤这些缺陷上传 Web shell 以进⾏远程代码执⾏。我们甚⾄创建了⼀些交互式的、故意易受攻击的实验室,以便您可以针对⼀些现实⽬标练习您所学的内容。
Web 服务器如何处理对静态⽂件的请求?
在我们研究如何利⽤⽂件上传漏洞之前,您必须对服务器如何处理静态⽂件请求有⼀个基本的了解。
从历史上看,⽹站⼏乎完全由静态⽂件组成,这些⽂件会在⽤户请求时提供给⽤户。因此,每个请求的路径可以与服务器⽂件系统上的⽬录和⽂件的层次结构 1:1 映射。如今,⽹站越来越动态,请求的路径通常与⽂件系统没有直接关系。尽管如此,Web 服务器仍会处理对⼀些静态⽂件的请求,包括样式表、图像等。
处理这些静态⽂件的过程仍然⼤致相同。在某些时候,服务器会解析请求中的路径以识别⽂件扩展名。然后它使⽤它来确定所请求⽂件的类型,通常通过将其与扩展名和 MIME 类型之间的预配置映射列表进⾏⽐较。接下来会发⽣什么取决于⽂件类型和服务器的配置。
如果此⽂件类型是不可执⾏的,例如图像或静态 HTML 页⾯,则服务器可能只是在 HTTP 响应中将⽂件的内容发送给客户端。
如果⽂件类型是可执⾏的,例如 PHP ⽂件,并且服务器被配置为执⾏这种类型的⽂件,它会在运⾏脚
本之前根据 HTTP 请求中的标头和参数分配变量。然后可以将结果输出以 HTTP 响应的形式发送到客户端。
如果⽂件类型是可执⾏的,但服务器没有配置为执⾏这种类型的⽂件,它通常会响应错误。但是,在某些情况下,⽂件的内容可能仍以纯⽂本形式提供给客户端。这种错误配置有时会被利⽤来泄露源代码和其他敏感信息。您可以在我们的学习材料 中看到⼀个这样的
⼩费
Content-Type响应标头可能会提供有关服务器认为它已提供的⽂件类型的线索 。如果应⽤程序代码没有明确设置此标头,它通常包含⽂件扩展名/MIME 类型映射的结果。
现在您已经熟悉了关键概念,让我们来看看您可以如何潜在地利⽤这些类型的漏洞。
利⽤不受限制的⽂件上传来部署 web shell
从安全⾓度来看,最糟糕的情况是⽹站允许您上传服务器端脚本,例如 PHP、Java 或 Python ⽂件,并且还配置为将它们作为代码执⾏。这使得在服务器上创建⾃⼰的 web shell 变得很简单。
⽹页外壳
Web shell 是⼀种恶意脚本,攻击者只需将 HTTP 请求发送到正确的端点,就可以在远程 Web 服务器上执⾏任意命令。
如果您能够成功上传 Web Shell,您就可以有效地完全控制服务器。这意味着您可以读取和写⼊任意⽂件、泄露敏感数据,甚⾄可以使⽤服务器对内部基础设施和⽹络外的其他服务器进⾏攻击。例如,以下 PHP one-liner 可⽤于从服务器的⽂件系统中读取任意⽂件:
<?php echo file_get_contents('/path/to/target/file'); ?>
上传后,发送对该恶意⽂件的请求将在响应中返回⽬标⽂件的内容。
实验室未解决
⼀个更通⽤的 web shell 可能看起来像这样:
<?php echo system($_GET['command']); ?>
此脚本使您能够通过查询参数传递任意系统命令,如下所⽰:
GET /example/exploit.php?command=id HTTP/1.1
利⽤有缺陷的⽂件上传验证
在野外,您不太可能到⼀个⽹站,它对⽂件上传攻击没有任何保护,就像我们在之前的实验室中看到的那样。但仅仅因为防御措施到位,并不意味着它们是强⼤的。
在本节中,我们将研究 Web 服务器尝试验证和清理⽂件上传的⼀些⽅法,以及如何利⽤这些机制中的缺陷来获取⽤于远程代码执⾏的Web shell。
有缺陷的⽂件类型验证
提交 HTML 表单时,您的浏览器通常会POST在内容类型为 的请求中发送提供的数据application/x-www-form-url-encoded。这适⽤于发送您的姓名、地址等简单⽂本,但不适⽤于发送⼤量⼆进制数据,例如整个图像⽂件或 PDF ⽂档。在这种情况下,内容类型multipart/form-data是⾸选⽅法。
考虑⼀个包含⽤于上传图像、提供图像描述和输⼊⽤户名的字段的表单。提交此类表单可能会导致请求如下所⽰:
POST /images HTTP/1.1
Host: normal-website
Content-Length: 12345
Content-Type: multipart/form-data; boundary=---------------------------012345678901234567890123456
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="image"; filename="example.jpg"
Content-Type: image/jpeg
[...binary content of ]
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="description"
This is an interesting description of my image.
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="username"
wiener
---------------------------012345678901234567890123456--
如您所见,消息正⽂被拆分为每个表单输⼊的单独部分。每个部分都包含⼀个Content-Disposition标题,该标题提供了有关与其相关的输⼊字段的⼀些基本信息。这些单独的部分也可能包含它们⾃⼰的Content-Type标头,它告诉服务器使⽤此输⼊提交的数据的 MIME 类型。
⽹站可能尝试验证⽂件上传的⼀种⽅法是检查此特定于输⼊的Content-Type标头是否与预期的 MIME 类型匹配。例如,如果服务器只需要图像⽂件,它可能只允许image/jpeg和之类的类型image/png。当此标头的值被服务器隐式信任时,可能会出现问题。如果不执⾏进⼀步的验证来检查⽂件的内容是否实际匹配假定的 MIME 类型,则可以使⽤ Burp Repeater 等⼯具轻松绕过这种防御。
实验: 未解决
防⽌在⽤户可访问的⽬录中执⾏⽂件
虽然⾸先防⽌危险⽂件类型被上传显然更好,但第⼆道防线是阻⽌服务器执⾏任何通过⽹络溜⾛的脚本。
作为预防措施,服务器通常只运⾏其 MIME 类型已明确配置为执⾏的脚本。否则,它们可能只是返回某种错误消息,或者在某些情况下,将⽂件内容作为纯⽂本提供:
GET /static/exploit.php?command=id HTTP/1.1
Host: normal-website
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 39
<?php echo system($_GET['command']); ?>
这种⾏为本⾝可能很有趣,因为它可能会提供⼀种泄漏源代码的⽅法,但它会使任何创建 Web shell 的尝试⽆效。
这种配置通常在⽬录之间有所不同。⽤户提供的⽂件上传到的⽬录可能⽐⽂件系统上假定最终⽤户⽆法访问的其他位置具有更严格的控制。如果您能到⼀种⽅法将脚本上传到不应该包含⽤户提供的⽂件的不同⽬录,那么服务器最终可能会执⾏您的脚本。
unicode文件格式⼩提⽰
Web 服务器经常使⽤请求中的filename字段multipart/form-data来确定⽂件应保存的名称和位置。
实验 : 未解决
您还应该注意,即使您可以将所有请求发送到同⼀个域名,这通常指向某种反向代理服务器,例如负载均衡器。您的请求通常由幕后的其他服务器处理,这些服务器的配置也可能不同。
危险⽂件类型的⿊名单不⾜
防⽌⽤户上传恶意脚本的最明显⽅法之⼀是将具有潜在危险的⽂件扩展名(如.php. ⿊名单的做法本质上是有缺陷的,因为很难明确阻⽌每个可能⽤于执⾏代码的⽂件扩展名。有时可以通过使⽤鲜为⼈知的替代⽂件扩展名绕过此类⿊名单,这些扩展名可能仍然是可执⾏的,例如.php5,.shtml等。
覆盖服务器配置
正如我们在上⼀节中所讨论的,服务器通常不会执⾏⽂件,除⾮它们已被配置为这样做。例如,在 Apache 服务器执⾏客户端请求的 PHP ⽂件之前,开发⼈员可能必须将以下指令添加到他们的/etc/f⽂件中:
LoadModule php_module /usr/lib/apache2/modules/libphp.so
AddType application/x-httpd-php .php
许多服务器还允许开发⼈员在各个⽬录中创建特殊的配置⽂件,以便覆盖或添加⼀个或多个全局设置。例如,Apache 服务器将从⼀个名为(.htaccess如果存在)的⽂件中加载特定于⽬录的配置。
同样,开发⼈员可以使⽤fig⽂件在 IIS 服务器上进⾏特定于⽬录的配置。这可能包括如下指令,在这种情况下允许将 JSON ⽂件提供给⽤户:
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
Web 服务器在存在时使⽤这些类型的配置⽂件,但通常不允许您使⽤ HTTP 请求访问它们。但是,您可能偶尔会发现⽆法阻⽌您上传⾃⼰的恶意配置⽂件的服务器。在这种情况下,即使您需要的⽂件扩展名被列⼊⿊名单,您也可以欺骗服务器将任意⾃定义⽂件扩展名映射到可执⾏的 MIME 类型。
实验 : 未解决
混淆⽂件扩展名
即使是最详尽的⿊名单也可能被经典的混淆技术绕过。假设验证代码区分⼤⼩写并且⽆法识别它exploit.pHp实际上是⼀个.php⽂件。如果随后将⽂件扩展名映射到 MIME 类型的代码不区分⼤⼩写,则这种差异允许您将恶意 PHP ⽂件偷偷通过验证,最终可能由服务器执⾏。
您还可以使⽤以下技术获得类似的结果:
提供多个扩展。根据⽤于解析⽂件名的算法,以下⽂件可能被解释为 PHP ⽂件或 JPG 图像:exploit.php.jpg
添加尾随字符。⼀些组件会去除或忽略尾随空格、点等:exploit.php.
尝试对点、正斜杠和反斜杠使⽤ URL 编码(或双 URL 编码)。如果在验证⽂件扩展名时该值没有被解码,但后来在服务器端被解码,这也可以让您上传否则会被阻⽌的恶意⽂件:exploit%2Ephp
在⽂件扩展名前添加分号或 URL 编码的空字节字符。如果验证是⽤ PHP 或 Java 等⾼级语⾔编写的,但服务器使⽤ C/C++ 中的低级函数处理⽂件,例如,这可能会导致⽂件名结尾出现差异:exploit.asp;.jpg或exploit.asp%00.jpg
尝试使⽤多字节 unicode 字符,在 unicode 转换或规范化后可能会转换为空字节和点。xC0 x2E如果⽂件名被解析为 UTF-8 字符串,则类似xC4 xAE或的序列xC0 xAE可能会被转换为x2E,但随后会在⽤于路径之前转换为 ASCII 字符。
其他防御措施包括剥离或替换危险的扩展名以防⽌⽂件被执⾏。如果不递归地应⽤此转换,您可以定位禁⽌的字符串,以便删除它仍然留下有效的⽂件扩展名。例如,考虑.php从以下⽂件名中剥离会发⽣什么:
exploit.p.php hp
这只是混淆⽂件扩展名的众多⽅法中的⼀⼩部分。
实验 :未解决
有缺陷的⽂件内容验证
更安全的服务器不会隐式信任Content-Type请求中指定的内容,⽽是尝试验证⽂件的内容是否与预期内容实际匹配。
在图像上传功能的情况下,服务器可能会尝试验证图像的某些内在属性,例如其尺⼨。例如,如果您
尝试上传 PHP 脚本,则它根本没有任何维度。因此,服务器可以推断它不可能是图像,并相应地拒绝上传。
同样,某些⽂件类型可能总是在其页眉或页脚中包含特定的字节序列。这些可以⽤作指纹或签名来确定内容是否与预期的类型匹配。例
如,JPEG ⽂件总是以 bytes 开头FF D8 FF。
这是⼀种更可靠的⽂件类型验证⽅法,但即使这样也不是万⽆⼀失的。使⽤ ExifTool 等特殊⼯具,可以轻松创建包含元数据中恶意代码的多语⾔ JPEG ⽂件。
实验 : 未解决
利⽤⽂件上传竞争条件
现代框架更能抵御此类攻击。他们通常不会将⽂件直接上传到⽂件系统上的预期⽬的地。相反,他们采取了预防措施,例如⾸先上传到临时的沙盒⽬录并随机命名以避免覆盖现有⽂件。然后,他们对这个临时⽂件执⾏验证,只有在认为安全的情况下才将其传输到⽬的地。
也就是说,开发⼈员有时会独⽴于任何框架来实现⾃⼰的⽂件上传处理。做好这件事不仅相当复杂,⽽且还可能引⼊危险的竞争条件,使攻击者能够完全绕过最强⼤的验证。
例如,⼀些⽹站直接将⽂件上传到主⽂件系统,如果没有通过验证,则再次将其删除。这种⾏为在依赖防病毒软件等检查恶意软件的⽹站中很常见。这可能只需要⼏毫秒,但在⽂件存在于服务器上的短时间内,攻击者仍有可能执⾏它。
这些漏洞通常⾮常微妙,因此在⿊盒测试期间很难检测到,除⾮您能到泄漏相关源代码的⽅法。
实验室未解决
基于 URL 的⽂件上传中的竞争条件
在允许您通过提供 URL 来上传⽂件的函数中可能会出现类似的竞争条件。在这种情况下,服务器必须通过 Internet 获取⽂件并创建本地副本,然后才能执⾏任何验证。
由于⽂件是使⽤ HTTP 加载的,因此开发⼈员⽆法使⽤其框架的内置机制来安全地验证⽂件。相反,他们可以⼿动创建⾃⼰的流程来临时存储和验证⽂件,这可能不太安全。
例如,如果⽂件被加载到具有随机名称的临时⽬录中,理论上,攻击者应该不可能利⽤任何竞争条件。如果他们不知道⽬录的名称,他们将⽆法请求⽂件以触发其执⾏。另⼀⽅⾯,如果随机⽬录名称是使⽤ PHP 之类的伪随机函数⽣成的uniqid(),则它可能会被暴⼒破解。
为了使此类攻击更容易,您可以尝试延长处理⽂件所需的时间,从⽽延长暴⼒破解⽬录名称的窗⼝。⼀种⽅法是上传更⼤的⽂件。如果它以块的形式进⾏处理,您可以通过在开始时创建⼀个带有有效负载的恶意⽂件,然后是⼤量的任意填充字节来利⽤这⼀点。
⽆需远程执⾏代码即可利⽤⽂件上传漏洞
在我们⽬前看到的⽰例中,我们已经能够上传服务器端脚本以进⾏远程代码执⾏。这是不安全的⽂件上传功能最严重的后果,但这些漏洞仍然可以通过其他⽅式被利⽤。
上传恶意客户端脚本
尽管您可能⽆法在服务器上执⾏脚本,但您仍然可以上传脚本以进⾏客户端攻击。例如,如果您可以上传 HTML ⽂件或 SVG 图像,则可以使⽤<script>标签来创建有效负载。
如果上传的⽂件随后出现在其他⽤户访问的页⾯上,则他们的浏览器将在尝试呈现页⾯时执⾏脚本。请注意,由于限制,这些类型的攻击只有在上传的⽂件是从您上传⽂件的同⼀源提供时才会起作⽤。
利⽤上传⽂件解析中的漏洞
如果上传的⽂件看起来既安全⼜安全,最后的⼿段是尝试利⽤特定于解析或处理不同⽂件格式的漏洞。
例如,您知道服务器解析基于 XML 的⽂件,例如 Microsoft Office.doc或.xls⽂件,这可能是攻击的潜在载体。
使⽤ PUT 上传⽂件
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论