0


PortSwigger web实验室(BurpSuit官方靶场)之文件上传漏洞

前言

Hi~ o( ̄▽ ̄)ブ,我是一名刚刚开始学习网安的新手。在做PortSwigger实验室(也就是BurpSuit官方做的靶场和学习中心)题目的时候发现对于新手来说还是有很多问题的。上网搜索相关文章发现可能是官方跟新了靶场的题目,导致很多文章已经“货不对板”了。思来想去最后决定自己来写一篇通关文章!如果有什么地方写的不好或者有什么错误欢迎大伙指出批评~~

ps:该文章包含大量我作为初学者在解题过程中的学习过程和内容,可能会显得很臃肿。如果只是寻找简洁的通关攻略的朋友可能就不太适合啦~~作为初学者很多地方可能写的不够详细或者有错误,希望大家能在评论区积极讨论嘻嘻(●’◡’●)

另外,文中大部分内容是对web security academy中原文的翻译。文中内容如有侵权请联系作者删除。

靶场地址

https://portswigger.net/web-security/learning-paths/server-side-vulnerabilities-apprentice

主页

文件上传漏洞

什么是文件上传漏洞?

文件上传漏洞是指Web服务器允许用户将文件上传到其文件系统,而无需充分验证其名称,类型,内容或大小等内容。如果没有适当地执行这些限制,可能意味着即使是基本的图像上传功能也可以用来上传任意和潜在危险的文件。这甚至可以包括支持远程代码执行的服务器端脚本文件。

在某些情况下,上传文件的行为本身就足以造成损害。其他攻击可能涉及对文件的后续HTTP请求,通常是为了触发服务器执行该文件。

文件上传漏洞是如何产生的?

大部分网站都对用户可以上传等文件做了限制,开发人员与测试人员会在上线前进行验证。但是,很多时候开发人员实现了他们认为是健壮的用户文件上传验证,实际上这些对用户上传的文件进行验证的逻辑要么是有缺陷的,要么是很容易被绕过的。

例如,他们可能试图列入危险文件类型的黑名单,但未考虑检查文件扩展名时的解析差异。与任何黑名单一样,还很容易意外地漏掉一些可能仍然危险的更隐秘的文件类型。

还有,网站可能会尝试通过验证攻击者使用Burp Proxy或Repeater等工具就可以轻松操纵的属性来检查文件类型。

即使有强大的验证措施,这些措施可能在构成网站的主机和目录网络中应用得不一致,导致可以被利用的差异。

利用无限制的文件上传来部署Web Shell

从安全角度来看,最糟糕的情况是当一个网站允许上传服务器端脚本,比如PHP、Java或Python文件,并且还配置成可以将它们作为代码执行。这使得在服务器上轻松创建自己的Web Shell 成为可能。

Web Shell
Web Shell是一种恶意脚本,攻击者只需向特定的端点发送HTTP请求,即可在远程Web服务器上执行任意命令。

如果你成功上传了Web Shell,你实际上就拥有对服务器的完全控制权。这意味着你可以读写任意文件,窃取敏感数据,甚至使用服务器来对内部基础设施和网络外的其他服务器进行攻击。

例如,以下PHP一行代码可用于从服务器文件系统中读取任意文件的内容:

<?phpechofile_get_contents('/path/to/target/file');?>

一旦上传完成,发送对该恶意文件的请求将在响应中返回目标文件的内容。

一个更灵活通用的Web Shell 可能如下所示:

<?phpechosystem($_GET['command']);?>

这个脚本使你能够通过查询参数传递任意系统命令,例如:

GET /example/exploit.php?command=id HTTP/1.1

实验:通过Web Shell上传远程执行代码

通过web shell上传远程执行代码关卡页面

首先利用题目给的账号密码进行登录进入到文件上传页面。

上传界面
可以用到上面的payload进行一些改造,利用php的

file_get_contents()

方法获取我们要的内容。

上传文件内容
上传完成

因为上传的文件原本是头像,所以可以在有头像显示的地方看到它是怎么获取到“头像”文件的。

找到文件的位置

使用GET请求访问文件,成功拿到内容。

访问结果
成功咯

利用文件上传验证的缺陷

在实际应用中,不太可能找到像我们在上一个实验中看到的那样没有针对文件上传攻击的保护的网站。但仅仅有一些防御措施并不意味着它们是强大的。有时候,你仍然可以利用这些机制中的漏洞来获取用于远程代码执行的Web Shell。

不完善的文件类型验证

当提交HTML表单时,浏览器通常在内容类型为

application/x-www-form-url-encoded 

POST 

请求中发送所提供的数据。这对于发送简单的文本数据,如姓名或地址,是可以的。然而,它并不适用于发送大量的二进制数据,比如整个图像文件或PDF文档。在这种情况下,更适用的是内容类型

multipart/form-data

Post请求的编码格式

  • application/x-www-form-urlencoded (表单 URL 编码) 这是用于在 HTML 表单中发送简单文本数据的默认方式。在这种编码中,所有的字符都会被转换为其 URL 编码形式(例如,空格会被转换为 %20),然后以键值对的形式发送(在一些其情况下,编码格式为:将键值对的参数用&连接起来,如果有空格,将空格转换为+加号;有特殊符号,将特殊符号转换为ASCII HEX值)。这种方式适用于发送短小的文本数据,比如用户输入的用户名和密码。
  • multipart/form-data(多部分表单数据) 这是用于在 HTML 表单中发送二进制数据或大量文本数据的一种方式。在这种编码中,数据被分成多个部分,每个部分都有自己的边界(boundary),并且可以包含二进制数据。这种方式通常用于上传文件,如图像或文档。它允许更灵活地处理不同类型的数据,而不仅仅是简单的键值对。

本文在此不做过多赘述,具体可以参考Hello_Error大佬的文章:https://blog.csdn.net/u013258447/article/details/101107743

设计一个表单,其中需要包含用于上传图像、提供图像描述和输入用户名的字段。提交这样的表单可能会导致如下所示的请求:

POST/images HTTP/1.1Host: normal-website.com
Content-Length:12345Content-Type: multipart/form-data; boundary=---------------------------012345678901234567890123456---------------------------012345678901234567890123456Content-Disposition: form-data; name="image"; filename="example.jpg"Content-Type: image/jpeg

[...binary content of example.jpg...]---------------------------012345678901234567890123456Content-Disposition: form-data; name="description"This is an interesting description of my image.---------------------------012345678901234567890123456Content-Disposition: form-data; name="username"

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

正如我们所看到的,消息体被分割为表单的每个输入的单独部分。每个部分都包含一个 Content-Disposition 头,它提供了与之相关的输入字段的一些基本信息。这些单独的部分也可能包含它们自己的 Content-Type 头,它告诉服务器使用此输入提交的数据的MIME类型。

MIME类型

  • MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。
  • 浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理URL,因此 Web服务器在响应头中添加正确的 MIME 类型非常重要。如果配置不正确,浏览器可能会无法解析文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。
  • MIME类型的通用结构type/subtype,MIME 的组成结构非常简单,由类型与子类型两个字符串中间用 / 分隔而组成,不允许有空格。type 表示可以被分多个子类的独立类别,subtype 表示细分后的每个类型。
  • 两种主要的 MIME 类型在默认类型中扮演了重要的角色: - text/plain 表示文本文件的默认值。- application/octet-stream 表示所有其他情况的默认值。
  • 常见的MIME类型 - 超文本标记语言文本 .html、.html:text/html- 普通文本 .txt: text/plain- RTF 文本 .rtf: application/rtf- GIF 图形 .gif: image/gif- JPEG 图形 .jpeg、.jpg: image/jpeg- au 声音文件 .au: audio/basic- MIDI 音乐文件 mid、.midi: audio/midi、audio/x-midi- RealAudio 音乐文件 .ra、.ram: audio/x-pn-realaudio- MPEG 文件 .mpg、.mpeg: video/mpeg- AVI 文件 .avi: video/x-msvideo- GZIP 文件 .gz: application/x-gzip- TAR 文件 .tar: application/x-tar

网站可能尝试验证文件上传的一种方法是检查此输入特定的 Content-Type 头是否与预期的MIME类型匹配。例如,如果服务器只需要图像文件,它可能只允许像 image/jpeg 和 image/png 这样的类型。当服务器隐式信任此标头的值时,可能会出现问题。如果不执行进一步的验证来检查文件的内容是否确实与假定的MIME类型匹配,则可以使用Burp Repeater之类的工具轻松绕过此防御。

实验:通过内容类型限制绕过Web shell上传

通过内容类型限制绕过Web shell上传

我们按照上面类似的流程,再次进行文件上传。这次在上传头像前使用bp进行拦截即将发出的报文。(截获到如下报文)

截获的报文

可以清晰的看到类似我们上面举例中出现的报文结构,此时可以看到有关我们payload部分的Content-Type内容是application/octet-stream,我们将其求改为image/jpeg或image/png。

为什么这里知道需要的类型是image/jpeg?这里是根据经验猜测的,因为头像应该需要的是图片的类型。不过我们也可以通过使用尝试正常上传来看报文中正确的类型是什么或者随意上传根据响应报文来判断服务器希望接收的类型。例如在这个实例中服务器对于错误的类型会响应:Sorry, file type application/octet-stream is not allowed Only image/jpeg and image/png are allowed Sorry, there was an error uploading your file.

修改后的报文

上面便是修改后的报文,红色部分便是我们上传文件的内容。完成上传后收到如下响应表示成功。

上传成功后
接下来依旧是上面的套路,访问我们上传的文件来让其执行。提交下面获得的信息就通关了!

响应

到这里关于文件上传的内容就结束啦!蟹蟹大家看到这里!


本文转载自: https://blog.csdn.net/weixin_60677557/article/details/134980482
版权归原作者 忆南平 所有, 如有侵权,请联系我们删除。

“PortSwigger web实验室(BurpSuit官方靶场)之文件上传漏洞”的评论:

还没有评论