【Portswigger 学院】文件上传

教程和靶场来源于 Burpsuite 的官网 Portswigger:File upload vulnerabilities - PortSwigger

原理与危害

很多网站都有文件上传的功能,比如在个人信息页面允许用户上传图片作为头像。如果网站应用程序对用户上传的文件没有针对文件名、文件类型、文件内容或文件大小做充分的验证,就可能导致允许攻击者上传有潜在危险的文件,比如服务端的脚本文件,然后访问该文件以触发代码执行。

文件上传漏洞的危害取决于两个因素:

  • 网站应用程序对文件名、文件类型、文件内容或文件大小等参数中的哪一个没有做充分的验证。
  • 上传文件成功后受到哪些限制。

最坏的情况是文件类型没有受到服务器的任何限制,允许 .php.jsp 作为脚本文件执行,那么攻击者可以上传 .php.jsp 文件作为 webshell,接管服务器。

其他的一些危害:

  • 对文件名没有做验证,攻击者上传一个同名的文件,覆盖服务器上已存在的文件,如果还存在路径遍历漏洞,那么危害更大,可以覆盖服务器的系统文件。
  • 对文件大小没有做验证,攻击者上传一个非常大的文件,占用服务器的磁盘空间,也就是 DoS 攻击。

由于文件上传漏洞的危害很大,所以现在大部分网站应用程序都做了防御,能直接上传 .php.jsp 文件的网站很少看到了。然而,漏洞仍然会产生,这是因为开发人员坚信他们的防御足够有效。

静态文件处理

在刚学习 Web 安全时,看了很多课程和书籍,我们潜意识认为一个 URL 对应网站服务器上的一个文件,对应关系是 1:1,比如 http://example.com/includes/func.php 这个 URL 在网站服务器上对应的文件位于网站根目录下的 includes 目录下的 func.php 文件。这种理解在以前静态网站甚至 PHP 网站和 ASP 网站流行的时候确实是这样,这只不过是 Apache 或 IIS 等中间件正好这样管理站点的文件,但是现代 Web 应用程序已经不是这样 URL 与文件呈现一对一的映射关系,我们现在看到一个 URL 比如  https://csdn.net/mp_blog/creation/editor,在网站服务器并不存在一个路径为 <网站根目录>/mp_blog/creation/editor 的文件

当然,像图片、CSS 和 JS 等静态资源,Web 服务器仍然用一对一的映射关系处理它们,处理步骤是:解析 URL 中的 path 部分,识别出请求的文件的扩展名,然后根据扩展名匹配对应的 MIME,最后根据服务器预先的配置执行下一步:

  • 如果文件类型是不可执行的,就作为静态文件把文件内容响应给客户端。
  • 如果文件类型是可执行的,例如 PHP 文件,就创建运行环境,根据请求头和请求参数分配变量,然后执行脚本。
  • 如果文件类型是可执行的,但服务器被配置成不执行该类型的文件,就给客户端响应一个错误。不过,大多数情况下,服务器仍然把这些当成普通文本,将它们的内容返回给客户端,这一点特性可能被利用实现泄露代码或其他敏感信息的目的。

实验

实验说明:

服务器没有对上传的文件没做任何验证,上传一个 PHP 脚本并读取 /home/carlos/secret 文件的内容就能完成实验。

进入实验场景:

用账号 wiener:peter 登录,进入个人信息页面:

点击最下面的“浏览”按钮,选择一个 PHP 脚本上传,PHP 脚本的内容:

<?php echo file_get_contents("/home/carlos/secret"); ?>

读取并返回 /home/carlos/secret 文件的内容。

点击“Upload”按钮上传文件,响应结果:

结果表示文件上传成功并给出保存的文件路径。除了这里可以看到保存的文件路径,还可以返回个人信息页面打开 F12 查看路径:

访问 /files/avatars/info.php 就能读取到 /home/carlos/secret 文件的内容:

复制这段数据,返回到首页点击 “Submit solution” 按钮提交即可。

绕过验证机制

Content-Type 伪造

提交表单后客户端发送一个 POST HTTP 请求,Content-Type 是请求包中的一个请求头,表示请求体的内容类型,如果是发送一段简短的文本,Content-Type 的值一般是 application/x-www-form-url-encoded,但如果发送的是一个大文件,比如 PDF,那么就得用文件上传的方式发送,此时的 Content-Type 是 multipart/form-data,表示表单数据多个部分,而 HTTP 请求包内容类似于这样:

POST /images HTTP/1.1
Host: normal-website.com
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 example.jpg...]

---------------------------012345678901234567890123456
Content-Disposition: form-data; name="description"

This is an interesting description of my image.

---------------------------012345678901234567890123456
Content-Disposition: form-data; name="username"

wiener
---------------------------012345678901234567890123456--

表单中每个输入之间用一段 ---------------------------012345678901234567890123456 字符串分割,第一个输入是图片,它也有自己的 Content-Type,值是 image/jpeg,表示这部分属于图片类型。第二个输入是没有 Content-Type,其实它相当于一个请求参数,参数名是 decsription,参数值是 

This is an interesting description of my image.

第三个输入同上。

如果服务器在接受上传的文件时,根据 Content-Type 决定文件的类型,那么就能让攻击者利用伪造绕过。如图:

结合路径遍历漏洞

上传文件的存储目录可能被限制为不允许执行脚本,这的确是可以实现的配置。例如,Apache 服务器可以针对某个特定目录配置特性,只要在目录下放置一个 .htaccess 文件,里面配置如下的指令:

php_flag engine offphp_flag engine off

那么当前目录下的所有脚本被访问时都不会运行,而是当作普通文本返回。

尝试利用路径遍历漏洞绕过这个限制,把文件上传到存储目录的上一级目录:

访问该文件时注意它的路径,avatars/../info.php 其实就是 info.php。

这里用 URL 编码处理了斜杠,因为应用程序在保存上传之前对文件名做了一次 URL 解码处理:

<?php
$target_dir = "avatars/";
$target_file = urldecode($target_dir.$_FILES["avatar"]["name"]);

if (strpos($target_file, ".htaccess")) {
  echo "The upload of .htaccess files is prohibited.";
  http_response_code(403);
} else if (move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file)) {
  echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
  echo "Sorry, there was an error uploading your file.";
  http_response_code(403);
}
?>

如果没有做 URL 解码处理,文件名中的 ../..\ 会被去掉。我在本地做了一个测试,如图:

也就是说文件上传漏洞结合路径遍历漏洞需要满足一定的条件。

重写服务器配置

有些应用程序对文件上传功能的安全防护是设置一个后缀名黑名单,里面包含不允许上传的文件后缀名,但这仍然存在风险,因为无法囊括所有不合法的后缀名,比如 .php5.shtml 等等,这些可能会被忽略。另外,相关配置文件的文件名或后缀名也应该被列为黑名单。

大多数 Web 服务器并不是在一开始安装成功后就能执行文件的,像 Apache,要执行 PHP 脚本,需要在 /etc/apache2/apache2.conf 配置文件中添加如下指令:

LoadModule php_module /usr/lib/apache2/modules/libphp.so
    AddType application/x-httpd-php .php

意思是加载 php 模块,以及当访问后缀名为 .php 的文件时,作为 php 脚本执行。

不止 Apache,Nginx 和 IIS 也都是要做一些配置才能执行脚本。

除了 apache2.conf 这个系统级的配置文件,Apache 服务器允许在每个目录下放置一个 .htaccess 文件,在该文件中添加的指令可以覆盖和补充 apache2.conf 的配置。如果应用程序允许上传 .htaccess,那么就能利用它绕过安全防护,执行代码。

首先,第一步是先上传 .htaccess

文件内容:

AddType application/x-httpd-php .png

这表示 .png 后缀的文件也被当成 PHP 脚本执行。

第二步是上传包含 PHP 代码的 .png 文件:

最后一步是访问 phpinfo.png 文件,触发代码执行。

IIS 服务器也有一个类似的配置文件,名为 web.config,它的指令示例:

<staticContent>
    <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>

表示 .json 文件被当成 json 发送给客户端。

PS:通常,.htaccess 和 web.config 被从客户端禁止访问。

混淆文件后缀

下面列举一些混淆技巧:

  • 如果在验证文件后缀名是否合法时区分大小写,但是在后缀名映射 MIME 时不区分大小写,那么可尝试大写后缀,比如 exploit.pHpexploit.PHP 等。
  • 多后缀名,比如 exploit.php.jpg。(Apache 多后缀解析漏洞)
  • 末尾加点,比如 exploit.php.  。(Windows不允许文件名末尾有点,如果有,会自动去掉)
  • 在验证文件后缀名之前没有做 URL 解码处理,但是在之后做了,那么可用 URL 编码绕过安全验证,比如 exploit%2Ephp
  • 如果服务器用低级语言如 C/C++ 写的,那么可尝试空字节绕过,比如 exploit.asp%00.jpg
  • 结合 IIS 6.0 解析漏洞,如:exploit.asp;.jpg
  • 如果应用程序匹配到不合法的后缀名后只做一次删除处理,而不是递归删除,那么可双写后缀绕过,比如 exploit.p.phphp

下图是利用空字节绕过的一个例子:

下面是应用程序处理这个文件名的代码,我们看看如何处理这个 %00 的:

<?php
$target_dir = "avatars/";
$target_file = urldecode($target_dir . $_FILES["avatar"]["name"]);
$uploadOk = true;

$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));

if($imageFileType != "jpg" && $imageFileType != "png") {
  echo "Sorry, only JPG & PNG files are allowed\n";
  $uploadOk = false;
}

//去掉空字节及其后面的字符
$target_file = strtok($target_file, chr(0));

if ($uploadOk && move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file)) {
  echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
  echo "Sorry, there was an error uploading your file.";
  http_response_code(403);
}

这很容易看懂。然而,在实际的场景中,并不会有开发人员会这样处理文件名,让攻击者有利用空字节绕过的可能,更多是服务器由 C/C++ 开发时才有可能出现。

文件内容验证绕过

当应用程序不信任 Content-Type 所指示的那样判断一个文件的类型,可能会直接通过验证文件的内容来判断。对于这种情况,最简单的验证方式就是查看文件开头几个字节,这几个字节又称魔术数字,大多数类型的文件都会在开头设置独一无二的字节序列,比如 JPEG 文件的就是 FF D8 FF,这种验证方式很容易绕过,因为攻击者也能在脚本的开头放置这几个字节并且不会影响代码执行。

比较复杂的情况是,应用程序用一些图片处理函数来判断上传的文件的数据是否真的是合法的图片数据,比如获取图片的尺寸,脚本文件就不会有这种数据。但是,攻击者可以将代码嵌入到图片的一些数据区,这些数据区不会破坏图片本身的数据和图片的渲染,比如 JPEG 图片的注释部分,用 Exiftool 工具可以做到这些事情。(Exiftool 工具在 kali 系统中已默认安装)

Exiftool 将 PHP 代码嵌入到 JPG 图片的注释部分:

exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" test.jpg -o polyglot.php

意思是将 -Comment 参数指定的内容嵌入到 test.jpg 的注释部分,最后生成 polyglot.php 文件。

条件竞争上传文件

有些应用程序接收到上传的文件后先保存到网站的一个目录下,接着对文件的安全性做验证,如果文件被判断为不安全的就会删除该文件,这样的处理是有问题。在保存到目录后和被判断为不安全而删除之前存在一个时间空隙,攻击者在这段空隙访问所上传的文件就能执行该文件,这是能够做到,利用预先写好的程序快速不停地访问即可。

现代开发框架都内置了处理文件上传的组件,它们通常都能够阻止这类漏洞,其处理步骤是

  1. 把上传的文件保存到一个沙盒化的临时目录(这里的文件被隔离且无法被访问到并执行);
  2. 重命名为一个随机字符串以避免文件覆盖;
  3. 做安全性验证,如果文件被判断为安全的,就移动文件到最终保存的目录,否则就删除。

如果开发人员自己编写文件上传处理程序,那么就有可能存在这类漏洞。

攻击者很难在黑盒测试中找到这种漏洞,除非他能找到应用程序的源代码,通过审计发现这种漏洞。

另外,还有一种情况可能发生条件竞争文件上传漏洞,就是让用户提供一个 URL 来保存文件,这一般只能由开发人员自己编写处理程序,也必须先下载一份文件副本到本地,然后再做安全性验证,所以这种情况很容易出现漏洞。

如果上传的文件或通过 URL 下载的文件保存到一个具有随机名称的临时目录,这一般不太可能被攻击者知道,但如果临时目录是伪随机数,那么仍然有可能被攻击者用暴力破解的方法知道。

为了让条件竞争上传文件的攻击更容易,攻击者会上传一个恶意的大文件,里面填充大量无用字符,但不会影响到里面的代码被执行,应用程序处理这类大文件会处理得更久,那么文件在文件系统上停留的时间更久,也就更容易被攻击者趁机访问。

客户端攻击

能上传带有恶意代码的文件是最严重的漏洞,这是针对服务器的攻击,但文件上传也能用于针对客户端攻击。上传一个 HTML 文件或 SVG 图像,里面包含 XSS 代码,那么就相当于是一个存储型 XSS 漏洞了,然后把文件的 URL 发给受害者,因为域名是合法的,所以更容易被信任。(注意,上传的文件如果被保存到另一个网站,那么要考虑同源策略的影响)

PUT 文件上传

某些服务器被配置为允许 HTTP PUT 请求方法,这种请求方法是用于上传文件,攻击者可先用 OPTIONS 请求方法查看网站是否支持 HTTP PUT 请求方法,然后再尝试上传文件。

PUT 上传请求示例:

PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49

<?php echo file_get_contents('/path/to/file'); ?>

防护

下面是一些防护方法:

  • 使用后缀名白名单而不是黑名单,因为列举出所有允许的后缀名更容易。
  • 文件名不能包含 ../ 序列。
  • 重命名文件避免文件覆盖。
  • 对文件做完安全性验证再移动它到永久保存的目录,在此之前保存到临时目录。
  • 尽量使用框架内置的文件上传处理组件,而不是自己编写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/775716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决中型组织三个人力资源基础问题的方法

中型企业 (通常在700 - 5000名员工之间)是从中小企业发展起来的&#xff0c;但不称为大型企业。虽然个别市场取得了成功&#xff0c;但到2023年&#xff0c;中端市场经历了一个艰难的结局&#xff0c;受到了更广泛的经济挑战的影响。然而&#xff0c;它仍然具有灵活性和乐观性&…

24_嵌入式系统输入输出设备

目录 GPIO原理与结构 A/D接口基本原理 A/D接口原理 A/D转换的重要指标 D/A接口基本原理 D/A接口原理 DAC的分类 D/A转换器的主要指标 键盘接口基本原理 键盘接口原理 用I/O口实现键盘接口 显示接口基本原理 基本结构和特点 基本原理 LCD种类 市面上出售的LCD的类…

dtpay聚合支付系统在跨境支付场景中技术及业务方案

1 什么是跨境支付 我们从两个维度来分析什么是跨境支付&#xff0c;第一个维度我们从资金流向分析&#xff0c;国内的消费者在境外进行消费对于国内资金流来说这属于资金流出&#xff0c;这是跨境支付的第一种应用场景。第二个场景国外游客在国内进行消费&#xff0c;这属于资…

【ECCV 2024】首个跨模态步态识别框架:Camera-LiDAR Cross-modality Gait Recognition

【ECCV 2024】首个跨模态步态识别框架&#xff1a;Camera-LiDAR Cross-modality Gait Recognition 简介&#xff1a;主要方法&#xff1a;实验结果&#xff1a; 论文&#xff1a;https://arxiv.org/abs/2407.02038 简介&#xff1a; 步态识别是一种重要的生物特征识别技术。基…

【论文阅读】-- Strscope:不规则测量的时间序列数据的多尺度可视化

Stroscope: Multi-Scale Visualization of Irregularly Measured Time-Series Data 摘要1 引言2相关工作2.1&#xff08;大型&#xff09;时间序列数据可视化2.2 事件序列数据可视化2.3 评价 3问题分析3.1 数据集3.2 场景——现状3.3 设计流程3.4 设计原理 4 涟漪图&#xff1a…

十大排序:插入/希尔/选择/堆/冒泡/快速/归并/计数/基数/桶排序 汇总(C语言)

目录 前言非线性时间比较类插入排序(1) 直接插入排序(2) 希尔排序 选择排序(3) 选择排序优化版(4) 堆排序 交换排序(5) 冒泡排序(6) 快速排序hoare版本挖坑版前后指针版非递归版 归并排序(7) 归并排序递归版非递归版 线性时间比较类(8) 计数排序基数排序与桶排序 总结 前言 在计…

昇思25天学习打卡营第16天|文本解码原理——以MindNLP为例

在大模型中&#xff0c;文本解码通常是指在自然语言处理&#xff08;NLP&#xff09;任务中使用的大型神经网络模型&#xff08;如Transformer架构的模型&#xff09;将编码后的文本数据转换回可读的原始文本的过程。这些模型在处理自然语言时&#xff0c;首先将输入文本&#…

自闭症儿童的治疗方法有哪些?

身为星贝育园自闭症儿童康复学校的资深教育者&#xff0c;我深知自闭症谱系障碍&#xff08;ASD&#xff09;儿童的教育与治疗需要一个全面、个性化的方案。在星贝育园&#xff0c;我们致力于为孩子们提供一个充满爱与理解的环境&#xff0c;采用多种科学验证的教育方法&#x…

【Java11】变量的初始化和内存中的运行机制

成员变量的初始化和内存中的运行机制 系统加载类或创建类的实例时&#xff0c;系统自动为成员变量分配内存空间&#xff0c;然后自动为成员变量指定初始值。 class Person {public String name; // 实例变量public static int eyeNum; // 类变量 }var p1 Person(); var p2 …

动态线程池思想学习及实践

引言 在后台项目开发过程中&#xff0c;我们常常借助线程池来实现多线程任务&#xff0c;以此提升系统的吞吐率和响应性&#xff1b;而线程池的参数配置却是一个难以合理评估的值&#xff0c;虽然业界也针对CPU密集型&#xff0c;IO密集型等场景给出了一些参数配置的经验与方案…

MQ:RabbitMQ

同步和异步通讯 同步通讯: 需要实时响应,时效性强 耦合度高 每次增加功能都要修改两边的代码 性能下降 需要等待服务提供者的响应,如果调用链过长则每次响应时间需要等待所有调用完成 资源浪费 调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下…

【后端面试题】【中间件】【NoSQL】MongoDB查询优化2(优化排序、mongos优化)

优化排序 在MongoDB里面&#xff0c;如果能够利用索引来排序的话&#xff0c;直接按照索引顺序加载数据就可以了。如果不能利用索引来排序的话&#xff0c;就必须在加载了数据之后&#xff0c;再次进行排序&#xff0c;也就是进行内存排序。 可想而知&#xff0c;如果内存排序…

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】 1、前言2、环境3、事项了解&#xff08;1&#xff09;了解sem概念-了解官网消息&#xff08;2&#xff09;根据自己理解&#xff0c;设计几个使用方式&#xff08;3&#xff09;不建议运行…

DataWhale-吃瓜教程学习笔记 (七)

学习视频**&#xff1a;第6章-支持向量机_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第六章 支持向量机 - 算法原理 几何角度 对于线性可分数据集&#xff0c;找距离正负样本距离都最远的超平面&#xff0c;解是唯一的&#xff0c;泛化性能较好 - 超平面 - 几何间隔 例…

堆叠的作用

一、为什么要堆叠 传统的园区网络采用设备和链路冗余来保证高可靠性&#xff0c;但其链路利用率低、网络维护成本高&#xff0c;堆叠技术将多台交换机虚拟成一台交换机&#xff0c;达到简化网络部署和降低网络维护工作量的目的。 二、堆叠优势 1、提高可靠性 堆叠系统多台成…

ServiceImpl中的参数封装为Map到Mapper.java中查询

ServiceImpl中的参数封装为Map到Mapper.java中查询&#xff0c;可以直接从map中获取到key对应的value

【Python机器学习】处理文本数据——多个单词的词袋(n元分词)

使用词袋表示的主要缺点之一就是完全舍弃了单词顺序。因此“its bad&#xff0c;not good at all”和“its good&#xff0c;not bad at all”这两个字符串的词袋表示完全相同&#xff0c;尽管它们的含义相反。幸运的是&#xff0c;使用词袋表示时有一种获取上下文的方法&#…

LeetCode热题100刷题3:3. 无重复字符的最长子串、438. 找到字符串中所有字母异位词、560. 和为 K 的子数组

3. 无重复字符的最长子串 滑动窗口、双指针 class Solution { public:int lengthOfLongestSubstring(string s) {//滑动窗口试一下//英文字母、数字、符号、空格,ascii 一共包含128个字符vector<int> pos(128,-1);int ans 0;for(int i0,j0 ; i<s.size();i) {//s[i]…

全端面试题15(canvas)

在前端开发领域&#xff0c;<canvas> 元素和相关的 API 是面试中经常被提及的主题。下面是一些常见的关于 HTML5 Canvas 的面试问题及解答示例&#xff1a; 1. 什么是 <canvas> 元素&#xff1f; <canvas> 是 HTML5 引入的一个用于图形渲染的标签。它本身并…

能否免费使用Adobe XD?

Adobe XD不是免费的。Adobe 目前XD采用订阅模式&#xff0c;提供订阅模式 7 每天试用期结束后需要付费购买&#xff0c;具体价格根据不同的订阅计划确定&#xff0c;包括每月购买&#xff0c;包括 9.99 美元或每月 99.99 美元&#xff0c;或者选择购买Adobe CreativeCloud整体订…