【Portswigger 学院】文件上传

news2024/11/26 21:41:59

教程和靶场来源于 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.coloradmin.cn/o/1897578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2007年下半年软件设计师【下午题】试题及答案

文章目录 2007年下半年软件设计师下午题--试题2007年下半年软件设计师下午题--答案2007年下半年软件设计师下午题–试题

基于图像处理的滑块验证码匹配技术

滑块验证码是一种常见的验证码形式&#xff0c;通过拖动滑块与背景图像中的缺口进行匹配&#xff0c;验证用户是否为真人。本文将详细介绍基于图像处理的滑块验证码匹配技术&#xff0c;并提供优化代码以提高滑块位置偏移量的准确度&#xff0c;尤其是在背景图滑块阴影较浅的情…

C++入门 容器适配器 / stack queue模拟实现

目录 容器适配器 deque的原理介绍 stack模拟实现 queue模拟实现 priority_queue模拟实现 仿函数 容器适配器 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总 结)&#xff0c;该种模式是将一个类的接口转换成客户希望…

Rufus 制作启动盘 | 便携的工作空间

唠唠闲话 最近服务器硬盘故障多&#xff0c;在修复过程中&#xff0c;学习了一些操作&#xff0c;这里做个记录。本期主要介绍 U盘启动盘的制作&#xff0c;以及持久化存储。 U 盘启动盘 镜像选择 Ubuntu 的版本命名遵循 “Adjective Animal” 的模式&#xff0c;即 “形容…

数据驱动制造业升级,免费可视化工具成关键

制造业作为国民经济的支柱产业&#xff0c;正经历着前所未有的变革。数据&#xff0c;作为这场变革的核心驱动力&#xff0c;其重要性不言而喻。然而&#xff0c;面对海量且复杂的数据&#xff0c;如何高效、直观地将其转化为有价值的洞察&#xff0c;成为了众多制造企业亟待解…

C++ 栈-队列-优先级队列

目录 1 栈 2 队列 3 deque 介绍 4 优先级队列 5 反向迭代器 栈也是我们在C语言就模拟实现过的一种数据结构&#xff0c;在C中&#xff0c;栈其实和我们前面模拟实现过的string、vector等容器有一点区别&#xff0c;站起是不是容器&#xff0c;而是一种容器适配器&#xff0c;我…

【前端项目笔记】9 数据报表

数据报表 效果展示&#xff1a; 在开发代码之前新建分支 git checkout -b report 新建分支report git branch 查看分支 git push -u origin report 将本地report分支推送到云端origin并命名为report 通过路由的形式将数据报表加载到页面中 渲染数据报表基本布局 面包屑导航…

总结一下 .NET FrameWork 和 .NET Core 创建的项目的不同点

前言 从 Visual Studio 2022 开始&#xff0c;微软开始淡化 .NET Framework 的概念&#xff0c;在项目向导中&#xff0c;只有使用带 “.NET Framework” 的项目模板创建的才是 .NET Framework 项目&#xff0c;使用其他模板创建的都是 .NET Core 项目 比如&#xff0c;如果你…

【数据结构】06.栈队列

一、栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out)的原则。 压栈&#…

数据结构--单链表实现

欢迎光顾我的homepage 前言 链表和顺序表都是线性表的一种&#xff0c;但是顺序表在物理结构和逻辑结构上都是连续的&#xff0c;但链表在逻辑结构上是连续的&#xff0c;而在物理结构上不一定连续&#xff1b;来看以下图片来认识链表与顺序表的差别 这里以动态顺序表…

《梦醒蝶飞:释放Excel函数与公式的力量》8.8 STDEVP函数

8.8 STDEVP函数 STDEVP函数是Excel中用于计算总体数据的标准偏差的函数。标准偏差是统计学中的一个重要指标&#xff0c;用于衡量数据集中各数值偏离平均值的程度。总体标准偏差考虑了整个数据集&#xff0c;而不是样本。 8.8.1 函数简介 STDEVP函数用于返回总体数据的标准偏…

Java实现日志全链路追踪.精确到一次请求的全部流程

广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向. 实现效果如下: 一次查询即可找到所有关…

前端面试题13(API请求方法)

在前端JavaScript中&#xff0c;进行API请求主要可以通过几种方式来实现&#xff0c;最常见的是使用XMLHttpRequest&#xff08;较旧的方法&#xff09;、fetch&#xff08;现代浏览器推荐方法&#xff09;以及使用第三方库如axios或jQuery.ajax等。 1. XMLHttpRequest 这是最…

MPI hello world SSH 免密互联

目标&#xff1a; 我们想实现2台主机免密互联&#xff0c;将MPI Hello World跑起来 假设hostname是node01,node02,&#xff08;Linux shell窗口一般是UserNameHostName&#xff0c;node1和node2一定要和HostName一样&#xff09; hostname是/etc/hosts中的配置&#xff0c;如下…

工地/矿区/电力/工厂/环卫视频智能安全监控反光衣AI检测算法的原理及场景应用

一、引言 随着科技的快速发展&#xff0c;特别是在智能交通和安全生产领域&#xff0c;对于夜间或弱光环境下的人员识别和安全监控需求日益凸显。反光衣作为一种重要的安全装备&#xff0c;被广泛应用于道路施工、工地作业、夜间巡逻、安全生产等场景&#xff0c;旨在提高人员的…

【CUDA】 矩阵乘法 matMatMul

矩阵乘法 matMatMul 矩阵乘法是基本线性代数子程序&#xff08;BLAS&#xff09;的重要组成部分&#xff0c;而且线性代数中许多其他操作以此为基础。 图1是两个矩阵的乘法。 基础方法&#xff0c;正方形tile和长方形tile 基础方法 执行矩阵乘法的基础方法是使用单个线程执…

2021-06-15 protues(ISIS)脉冲发生器仿真仪表使用

缘由这个脉冲发生器怎么连线_编程语言-CSDN问答

STM32智能交通管理系统教程

目录 引言环境准备智能交通管理系统基础代码实现&#xff1a;实现智能交通管理系统 4.1 数据采集模块 4.2 数据处理与分析 4.3 控制系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通管理与优化问题解决方案与优化收尾与总结 1. 引言 智能交通管理系统利用STM32嵌…

【对顶堆 优先队列】295. 数据流的中位数

本文涉及知识点 对顶堆 优先队列 LeetCode295. 数据流的中位数 中位数是有序整数列表中的中间值。如果列表的大小是偶数&#xff0c;则没有中间值&#xff0c;中位数是两个中间值的平均值。 例如 arr [2,3,4] 的中位数是 3 。 例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 …

网络漏洞挖掘实测报告

关于作者&#xff1a;个人主页 网络漏洞挖掘实测报告 一、前言 网络漏洞挖掘是信息安全领域中至关重要的一环。通过挖掘和修复漏洞&#xff0c;可以有效地保护系统免受潜在的攻击和破坏。本报告旨在记录一次完整的网络漏洞挖掘实测过程&#xff0c;包括实施方法、过程、结果以…