THM-上传漏洞

作者:xiaowu 日期: 分类:xiaowu 浏览:383

配置在线练习环境

使用你喜欢的文本编辑器,打开设备上的 hosts 文件:

在 Linux 和 MacOS 上,hosts文件可以通过终端在 /etc/hosts 路径下找到。
在 Windows 上,hosts文件可以在 C:\Windows\System32\drivers\etc\hosts 路径下找到(可以不通过终端)。

在 Linux 或 MacOS 上,您将需要在终端界面使用 sudo 打开文件进行写入。
在 Windows 中,你需要用“ Run as Administrator”打开该文件(先在电脑中找到该文件)。

这里主要介绍在kali等linux系统中的操作方法:

使用命令,在hosts文件的内容末尾添加代码行:
echo 10.10.190.98    overwrite.uploadvulns.thm shell.uploadvulns.thm java.uploadvulns.thm annex.uploadvulns.thm magic.uploadvulns.thm jewel.uploadvulns.thm demo.uploadvulns.thm >>/etc/hosts

注意: 
如果你在此之前已经完成了上述步骤,那么你必须删除以前的host条目。
hosts文件中应该只有一行包含上述 URL。
例如,下面的示例将不起作用:10.10.10.10    overwrite.uploadvulns.thm shell.uploadvulns.thm java.uploadvulns.thm annex.uploadvulns.thm magic.uploadvulns.thm jewel.uploadvulns.thm demo.uploadvulns.thm10.10.190.98    overwrite.uploadvulns.thm shell.uploadvulns.thm java.uploadvulns.thm annex.uploadvulns.thm magic.uploadvulns.thm jewel.uploadvulns.thm demo.uploadvulns.thm

上传漏洞简介和一般利用方法

将文件上传到服务器的能力已经成为我们如何与 Web应用程序进行交互的一个组成部分。
无论是社交媒体网站的个人资料图片、上传到云存储的报告,还是在 Github 上保存项目,具有文件上传功能的应用程序都是无限的。

不幸的是,如果处理不当,文件上传也会在服务器中引发严重的漏洞,这可能会导致一系列麻烦的问题的出现。
如果攻击者设法上传并执行 shell,则可能导致完全的远程代码执行(Remote Code Execution,RCE)。
通过不受限制地上传到服务器(以及随意检索数据的能力) ,攻击者可以破坏或以其他方式改变现有内容——包括注入恶意网页,从而导致进一步的漏洞,如 XSS 或 CSRF。
通过上传任意文件,攻击者还可能使用服务器来承载和/或提供非法内容,或泄漏敏感信息。
实际上,攻击者如果能够将自己选择的文件上传到你的服务器上(没有任何限制) ,那么这种攻击实际上是非常危险的。

本文的目的是探讨由于不正确(或不充分)处理文件上传操作 而导致的一些漏洞。具体来说,我们将关注:
1.文件上传 覆盖服务器上的现有文件
2.文件上传 在服务器上上传和执行 Shell
3.文件上传 绕过客户端过滤
4.文件上传 绕过各种服务器端过滤
5.文件上传 欺骗内容类型验证检查

我们在网站上有一个文件上传点。我们将如何利用它?

与任何类型的黑客攻击一样,枚举是关键。我们对环境了解得越多,我们就能利用它更多的事情。查看页面的源代码可以很好地了解是否应用了任何类型的客户端过滤。使用Gobuster等目录暴力破解程序进行扫描通常有助于网络攻击,并可能揭示文件上传到的位置;Gobuster不再默认安装在 Kali 上,但可以随sudo apt install gobuster.使用Burpsuite拦截上传请求也会派上用场。Wappalyser等浏览器扩展可以提供有关您所定位的网站的有价值的信息,一目了然。

对网站如何处理我们的输入有了基本的了解后,我们就可以尝试浏览一下,看看我们可以上传什么,不能上传什么。如果网站采用客户端过滤,那么我们可以轻松查看过滤器的代码并尝试绕过它(稍后会详细介绍!)。如果网站有服务器端过滤,那么我们可能需要猜测过滤器正在寻找什么,上传文件,然后在上传失败时根据错误消息尝试稍微不同的操作。上传旨在引发错误的文件可以帮助解决此问题。 Burpsuite 或OWASP Zap等工具在此阶段非常有帮助。


覆盖服务器上的现有文件

当文件上传到服务器时,应执行一系列检查以确保文件不会覆盖服务器上已存在的任何内容。常见的做法是为文件分配一个新名称——通常是随机的,或者将上传的日期和时间添加到原始文件名的开头或结尾。或者,可以应用检查来查看文件名是否已存在于服务器上;如果同名文件已存在,则服务器将返回一条错误消息,要求用户选择不同的文件名。在保护现有文件不被覆盖时,文件权限也会发挥作用。例如,网页不应该对网络用户可写,从而防止它们被攻击者上传的恶意版本覆盖。

但是,如果不采取此类预防措施,那么我们可能会覆盖服务器上的现有文件。实际上,服务器上的文件权限很可能会防止这是一个严重的漏洞。也就是说,它仍然可能很麻烦,并且值得在渗透测试或 bug 狩猎环境中予以关注。

实践操作

任务要求:打开你的网页浏览器并导航到overwrite.uploadvulns.thm ,你的目标是用你自己上传的文件 覆盖服务器上的文件。

查看图片地址及名称

image.png

更改一张图片名称与他一样

image.png

然后上传,可以看到背景图片已经变为我们上传的图片,顺势爆出flag

image.png

远程代码执行

远程代码执行,顾名思义,就是允许我们在 Web 服务器上执行任意代码 虽然这可能是一个低权限的 Web 用户帐户(如 Linux 服务器上的 www-data账户) ,但是这仍然是一个非常严重的漏洞。 通过 Web 应用程序中的上传漏洞远程执行代码,往往利用的是上传与网站后端使用相同语言编写的程序(或者是服务器能够理解并能执行的另一种语言) 传统的后端语言是PHP,然而,其他后端语言也已经变得更加普遍(主要的例子有Python Django、Node.js 形式的 Javascript等) 值得注意的是,在路由应用程序中(路由是通过编程方式定义的应用程序,而不是映射到文件系统的应用程序)这种攻击方法变得更加复杂,发生的可能性也大大降低。 大多数现代 Web 框架都是通过编程方式实现路由的。 在利用文件上传漏洞时,有两种基本的方法可以在 Web 服务器上实现 RCE(远程代码执行):Webshell和反向/绑定 shell 实际上,一个功能完备的反向/绑定 shell 是攻击者的理想目标; 然而,有时候webshell可能是唯一可用的选择(例如在以下环境中:目标服务器对上传功能施加了文件长度限制,或者防火墙规则阻止任何基于网络的 shell) 作为一种通用的方法论,我们希望上传一种或另一种 shell,然后激活它,如果服务器允许,我们就能直接导航到该文件(限制不足的非路由应用程序); 或者以其他方式强制 webapp 为我们运行脚本(这在路由应用程序中是必需的)。

实践操作

#1使用上面屏幕截图中的语法在网站上运行 Gobuster 扫描。哪个目录看起来可能用于上传?

打开kali,用gobuster扫描目录

gobuster dir -u http://shell.uploadvulns.thm -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

image.png

发现/resources目录是文件上传点

#2在计算机上获取 Web shell 或反向 shell。服务器的 /var/www/ 目录中的标志是什么?

准备好一个反向shell文件(https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php )

将shell文件中的ip地址为攻击机的虚拟内部地址(https://tryhackme.com/access )

image.png

用自己的虚拟机监听端口

image.png

然后将上文的shell.php文件长传,然后访问该文件

image.png

成功反弹shell

image.png

然后根据题目找到flag

image.png

关于“过滤”的介绍

客户端过滤:

当我们谈论一个“客户端”的脚本时,在 Web 应用程序的环境中,我们的意思是它运行在用户的浏览器上,而不是运行在Web 服务器上。主流的客户端脚本语言是JavaScript 。

无论使用何种语言,客户端脚本都会在浏览器中运行,在文件上传的上下文中,这意味着过滤发生在文件上传到服务器之前。

理论上讲,这应该是件好事,然而,因为过滤是在我们的计算机上发生的,所以我们很容易绕过它。因此,像这样通过客户端过滤来验证上载的文件是否为恶意文件,本身就是一种高度不安全的方法。

服务器端过滤:

服务器端脚本将在服务器上运行。在传统上,PHP 是主要的服务器端语言(微软IIS的ASP则紧随其后),最近几年,其他几种服务端脚本语言(C # ,Node.js,Python,Ruby on Rails等等)也得到了广泛地应用。服务器端过滤往往更难绕过,因为你面前没有代码。

当代码在服务器上执行时,在大多数情况下,也不可能完全绕过过滤;所以我们必须在符合过滤的地方 形成一个有效载荷(payload),从而让服务器端仍然允许我们执行代码。

文件扩展名验证:

文件扩展名(理论上)用于标识文件的内容。 在实践中,它们很容易改变,所以实际上并没有多大意义。 然而,MS Windows 仍然使用它们来识别文件类型,尽管基于 Unix 的系统倾向于依赖其他方法, 检查文件扩展名的筛选器有两种工作方式。它们要么是黑名单扩展(即有一个不允许的扩展名列表) ,要么是白名单扩展(即有一个允许的扩展名列表,并拒绝所有其他扩展名)。

文件类型过滤:

文件类型过滤 类似于文件扩展名验证,但是更加密集,文件类型过滤会再次验证文件的内容是否可以上传。
我们将研究两种类型的文件类型验证:

MIME 验证: 

MIME (多用途 Internet 邮件扩展)类型用作文件的标识符——最初是在通过电子邮件作为附件传输时使用,现在也在通过 HTTP (S)传输文件时使用。 文件上传的 MIME 类型附加在请求的头部,看起来像这样

image.png

MIME类型遵循的格式为: < type >/< subtype > 。

 在上面的请求中,你可以看到图片“ Spaniel.jpg”已经上传到服务器。 作为一个合法的 JPEG 图像,这次上传的 MIME 类型是“ image/JPEG”。 文件的 MIME 类型可以在客户端和/或服务器端进行检查,但是,由于 MIME 是基于文件的扩展名的,因此也很容易绕过它。

魔术数字验证:

 魔术数字是确定文件内容的更准确的方法,尽管它们并非不可伪造。 文件的“魔术数字”是指标识文件内容 在文件内容开头位置的一串字节。 例如,一个 PNG 文件在文件的最顶部有这些字节:89 50 4E 47 0D 0A 1A 0A

image.png

与Windows系统不同的是,Unix系统使用魔法数字来识别文件。 Unix类型的系统 在处理文件上传时,会检查上传文件的魔法数字,以确保文件能够被安全接受。 这绝不是一个有保证的解决方案,但它比检查文件的扩展名更有效。

文件长度过滤:

文件长度过滤 用于防止通过上传表单将大型文件上传到服务器(因为这可能导致服务器资源短缺)。 在大多数情况下,当我们上传 shell 时,这不会给我们带来任何问题。 但是,值得注意的是,如果上传表单只希望上传一个非常小的文件,可能会有一个长度过滤,以确保遵守文件长度要求。 作为一个例子,我们前一个任务中的PHP反向shell文件 大小为5.4 Kb ——相对较小,但是如果表单期望的文件最大为2Kb,那么我们需要找到一个替代的 shell 来上传。

文件名过滤:

如前所述,上传到服务器的文件应该是唯一的。 通常这意味着向文件名添加一些随机字符,但是,另一种策略是检查服务器上是否已经存在同名文件,如果存在,则返回给用户一个错误提示。 此外,文件名应该在上传时进行消毒,以确保它们不包含任何“坏字符”,“坏字符”可能会在上传时对文件系统造成潜在的问题(例如,Linux 上的空字节或正斜杠,以及控制字符";" 和潜在的Unicode 字符......)。 这对我们来说意味着,在一个管理良好的系统上,我们上传后的文件不太可能与上传前的文件名称相同,所以要注意,如果你设法绕过了过滤,你可能还要找到上传后的shell。

文件内容过滤:

更复杂的过滤系统可能会扫描上传文件的全部内容,以确保文件不会在扩展名、 MIME 类型和 Magic Number上面进行欺骗。 这是一个明显比大多数基本过滤系统更复杂的过滤过程。

值得注意的是,这些过滤本身都不是完美的——它们通常会相互结合使用,提供一个多层过滤,从而大大提高了上传的安全性。这些过滤器的任何一个都可以单独应用于客户端、服务器端或两者兼而有之(同时应用在前端和后端)。

类似地,不同的框架和语言都有自己固有的过滤和验证上传文件的方法。因此,可能会出现特定于语言的漏洞。

例如,在 PHP 主要版本php5之前,通过附加一个null空字节能够绕过文件扩展名过滤,后面再跟有效的扩展名.php,从而形成一个恶意的php webshell文件。

还可以将 PHP 代码注入到本来有效的图像文件的 exif 数据中,然后强制服务器执行它。

绕过客户端过滤

有四种简单的方法可以绕过普通的客户端文件上传过滤器:

  1. 关闭浏览器中的 Javascript——只要网站不需要 Javascript 即可提供基本功能,这将起作用。如果完全关闭 Javascript 会导致网站完全无法工作,那么其他方法之一会更可取;否则,这可能是完全绕过客户端过滤器的有效方法。

  2. 拦截并修改传入的页面。使用 Burpsuite,我们可以拦截传入的网页并在其有机会运行之前删除 Javascript 过滤器。下面将介绍此过程。

  3. 拦截并修改文件上传。前面的方法在网页加载之前起作用,而此方法允许网页正常加载,但在文件上传已经通过(并被过滤器接受)后拦截文件上传。再次,我们将介绍在任务过程中使用此方法的过程。

  4. 将文件直接发送到上传点。当您可以使用诸如 之类的工具直接发送文件时,为什么要使用带有过滤器的网页curl?将数据直接发布到包含处理文件上传的代码的页面是完全绕过客户端过滤器的另一种有效方法。在本教程中,我们不会真正深入地介绍此方法,但是,此类命令的语法如下所示:curl -X POST -F "submit:<value>" -F "<file-parameter>:@<path-to-file>" <site>。要使用此方法,您首先要拦截成功的上传(使用 Burpsuite 或浏览器控制台)以查看上传中使用的参数,然后可以将其插入到上述命令中。

直接进入答题

任务要求:使用浏览器导航到java.uploadvulns.thm页面,并绕过过滤器获得一个反向 shell。

先进行目录爆破

gobuster dir -u http://java.uploadvulns.thm -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt


image.png

可以看出上传后的文件保存在/images目录里

然后进到上传页面,观察源码

image.png

未找到过滤文件,开始在js文件里寻找

image.png

只接收png文件

我们把shell文件后缀改成png.然后开始上传,抓包

image.png

在这里将其改成.php,然后发送,成功

image.png

然后本机开始监听,再进入刚才上传的文件,本机接收shell,然后查看flag

image.png

绕过服务器端过滤: 文件扩展名

客户端可以看到源码,但服务端看不到源码,因此只能靠大量测试来判断隔离了什么,下面是一个服务端的代码示例

<?php
    //Get the extension
    $extension = pathinfo($_FILES["fileToUpload"]["name"])["extension"];
    //Check the extension against the blacklist -- .php and .phtml
    switch($extension){
        case "php":
        case "phtml":
        case NULL:
            $uploadFail = True;
            break;
        default:
            $uploadFail = False;
    }
?>

在此实例中,代码正在查找最后一个句点(.)并使用该文件名确认扩展名,这就是我们要绕过的。

这些代码的其他工作方式包括: 搜索文件名中的第一个句点(.),或者在每个句点(.)后面分割文件名,检查是否有被列入黑名单的扩展名出现。

我们可以看到代码正在过滤掉.php 和.phtml 扩展名,因此,如果我们想要上传一个 PHP 脚本,我们将不得不寻找另一个扩展名。

PHP 的维基百科页面( https://en.wikipedia.org/wiki/PHP )提供了一些常见的扩展,我们可以尝试使用; 然而,实际上还有很多其他很少使用的扩展,网络服务器仍然可以识别出来,其中包括:

.php3, .php4, .php5, .php7, .phps, .php-s, .pht and .phar

实践操作

进行目录爆破,得到上传目录image.png

image.png

尝试修改shell文件扩展名进行绕过:

上传.jpg.php失败
上传.phar失败
上传.pht失败
上传.php-s失败
上传.phps失败
上传.php7失败
上传.php5成功

image.png

连接反向shell,获取shell

image.png

绕过服务器端过滤: 魔术数字

如前所述,幻数被用作更准确的文件标识符。文件的幻数是一串十六进制数字,并且始终是文件中的第一个数字。知道了这一点,就可以使用幻数来验证文件上传,只需读取前几个字节并将它们与白名单或黑名单进行比较即可。请记住,这种技术对于基于PHP 的网络服务器非常有效;但是,它有时可能会在其他类型的网络服务器上失败

直接答题

扫描目录

image.png

上传一个JPEG文件到目标站点,目标站点给的提示信息为 只接收gif文件:

image.png

因为gif是6个16进制数,所以需要改6位,现在https://en.wikipedia.org/wiki/List_of_file_signatures上找到gif对应签名

image.png

然后直接将对应码加在shell.php文件最上方

image.png

然后直接上传,由于本题无法访问文件存放位置,因此直接访问该文件http://magic.uploadvulns.thm/graphics/shell.php

同时设置监听,建立连接,找到flag

image.png

示例方法

我们现在已经看到了各种不同类型的过滤器——客户端和服务器端——以及文件上传攻击的一般方法。在下一个任务中,您将面临一个需要完成的黑盒文件上传挑战,因此让我们借此机会更深入地讨论解决此类挑战的示例方法。您可以开发自己的替代方法来替代此方法,但是,如果您不熟悉这种攻击,您可能会发现以下信息很有用。

我们将将此视为一个逐步的过程。假设我们有一个网站要对其进行安全审核。

  1. 我们要做的第一件事是从整体上看一下网站。使用浏览器扩展,例如前面提到的 Wappalyzer(或手动),我们将寻找 Web 应用程序可能使用的语言和框架构建的指标。请注意,Wappalyzer 并不总是 100% 准确。手动枚举的一个好的开始是向网站发出请求并使用 Burpsuite 拦截响应。诸如server或 之类的标头x-powered-by可用于获取有关服务器的信息。我们还会寻找攻击媒介,例如上传页面。

  2. 找到上传页面后,我们将进一步检查它。查看客户端脚本的源代码以确定是否有任何客户端过滤器需要绕过,这是一个很好的开始,因为这完全在我们的控制范围内。

  3. 然后我们将尝试完全无害的文件上传。从这里我们将查看如何访问我们的文件。换句话说,我们可以直接在上传文件夹中访问它吗?它是否嵌入到页面的某个位置?网站的命名方案是什么?如果位置不是很明显,那么 Gobuster 等工具可能会派上用场。这一步非常重要,因为它不仅提高了我们对所攻击的虚拟环境的了解,还为我们提供了一个基线“已接受”文件,我们可以在此基础上进行进一步的测试。

    • 这里一个重要的Gobuster-x开关是开关,它可以用来查找具有特定扩展名的文件。例如,如果您添加-x php,txt,htmlGobuster命令,该工具会将.php.txt、 和.html附加到所选单词列表中的每个单词,一次一个。如果您已成功上传有效负载并且服务器正在更改上传文件的名称,这将非常有用。

  4. 确定了如何以及在何处可以访问我们上传的文件后,我们将尝试恶意文件上传,绕过我们在第二步中发现的任何客户端过滤器。我们希望我们的上传被服务器端过滤器停止,但它给我们的错误消息对于确定我们的后续步骤非常有用。

假设我们的恶意文件上传已被服务器阻止,可以通过以下一些方法来确定可能存在哪种类型的服务器端过滤器:

  • 如果您可以成功上传一个完全无效的文件扩展名(例如 )的文件,testingimage.invalidfileextension那么服务器很可能正在使用扩展名黑名单来过滤可执行文件。如果此上传失败,则任何扩展过滤器都将在白名单上运行。

  • 尝试重新上传您最初接受的无辜文件,但这次将文件的幻数更改为您希望过滤的内容。如果上传失败,那么您就知道服务器正在使用基于幻数的过滤器。

  • 与上一点一样,尝试上传无辜的文件,但使用 Burpsuite 拦截请求并将上传的MIME类型更改为您希望过滤的内容。如果上传失败,那么您就知道服务器正在根据MIME类型进行过滤。

  • 枚举文件长度过滤器是上传一个小文件,然后逐渐上传更大的文件,直到达到过滤器的情况。那时您就会知道可接受的限制是多少。如果您非常幸运,那么原始上传的错误消息可能会直接告诉您大小限制是多少。请注意,较小的文件长度限制可能会阻止您上传我们迄今为止一直使用的反向 shell。

挑战任务

还是老规矩,进站先爆破

image.png

扫出来这几个,但能进去的只有/admin

然后进站观察源码,找到js过滤文件,有3处过滤

$(document).ready(function(){let errorTimeout;const fadeSpeed=1000;function setResponseMsg(responseTxt,colour){$("#responseMsg").text(responseTxt);if(!$("#responseMsg").is(":visible")){$("#responseMsg").css({"color":colour}).fadeIn(fadeSpeed)}else{$("#responseMsg").animate({color:colour},fadeSpeed)}clearTimeout(errorTimeout);errorTimeout=setTimeout(()=>{$("#responseMsg").fadeOut(fadeSpeed)},5000)}$("#uploadBtn").click(function(){$("#fileSelect").click()});$("#fileSelect").change(function(){const fileBox=document.getElementById("fileSelect").files[0];const reader=new FileReader();reader.readAsDataURL(fileBox);reader.onload=function(event){

			//Check File Size
			if (event.target.result.length > 50 * 8 * 1024){
				setResponseMsg("File too big", "red");			
				return;
			}
			//Check Magic Number
			if (atob(event.target.result.split(",")[1]).slice(0,3) != "ÿØÿ"){
				setResponseMsg("Invalid file format", "red");
				return;	
			}
			//Check File Extension
			const extension = fileBox.name.split(".")[1].toLowerCase();
			if (extension != "jpg" && extension != "jpeg"){
				setResponseMsg("Invalid file format", "red");
				return;
			}
  1. 文件大小超过50过滤

  2. 魔术数字不为jpeg过滤

  3. 文件扩展名不为.jpg或.jepg过滤

再通过wappalyzer插件判断该网站为js网站,因此需要js编写的shell文件,通过这个链接可下载 https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md#nodejs

下载完后配置自己的ip及端口

然后保存该后缀为.jpg,再打开hexeditor改前几位为jpeg魔术数字

image.png

此时该文件已经是jpeg文件了

image.png

然后可以上传文件,同时开始抓包

image.png

将base64的内容换成shelljs文件编码后的内容,点发送

成功发送,接下来扫描文件

通过首页背景图已知道图片文件储存在/content目录中,因此扫描该目录下后缀为.jpg的文件

image.png

在攻击机终端使用Netcat建立监听器,在目标站点下/admin页面中的输入框中输入../content/xxx.jpg ,建立反向shell,使用该shell界面查找flag文件并查看其内容:

image.pngimage.png

image.png

关键词:

网友评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。