文件包含漏洞(File Inclusion Vulnerability)是一种常见的安全漏洞,主要存在于应用程序中。当应用程序对用户输入的文件路径或文件名进行不充分或无效的验证和过滤时,攻击者可以通过操纵应用程序对文件路径的处理,将恶意文件包含到应用程序中执行。这种漏洞通常发生在动态网页中,攻击者通过在URL中注入恶意代码,使应用程序将恶意代码作为正常代码执行。什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含
文件包含漏洞的危害性很大,攻击者可以利用该漏洞窃取敏感信息、篡改数据、控制服务器等。具体来说,它可能带来的危害有:
- web服务器的文件被外界浏览,导致信息泄露。
- 脚本被任意执行,典型影响包括篡改网站、执行非法操作、攻击其他网站等。
文件包含漏洞主要分为两类:
- 本地文件包含(Local File Inclusion,LFI):攻击者通过构造恶意文件路径,使得应用程序加载并执行的是本地的文件。常见的本地文件包含漏洞发生在应用程序将用户输入的文件名直接拼接到文件路径的情况下,且没有对用户输入进行充分的验证和过滤。
- 远程文件包含(Remote File Inclusion,RFI):攻击者通过构造恶意的URL地址,使得应用程序加载并执行的是远程服务器上的文件。由于远程文件包含漏洞涉及到远程服务器的访问,因此攻击者需要能够控制远程服务器上的文件内容。
要防止文件包含漏洞,可以采取以下措施:
-
不信任用户输入:必须对用户提供的文件名或路径进行验证和过滤,以确保只允许有效的文件名或路径。
-
使用白名单机制:只允许应用程序访问特定目录或文件,拒绝所有其他访问。
-
文件路径隔离:将应用程序的文件存储区域与其他敏感文件分开,并确保只有应用程序具有适当的访问权限。
-
避免使用动态文件包含:尽量避免将用户提供的数据用于拼接文件路径,而是使用固定的路径或文件标识符。
-
更新和修补:及时更新和修补应用程序和操作系统,以修复已知的文件包含漏洞。
为了避免文件包含漏洞,开发人员在编写代码时应该对用户输入的文件路径或文件名进行严格的验证和过滤,确保只包含合法的文件路径和文件名。同时,应该避免使用不安全的文件包含函数,如PHP中的include()和require()函数,而应该使用更加安全的替代方案。此外,对于动态变量,应该进行充分的检查和过滤,确保它们不包含恶意代码或文件路径。
总之,要避免文件包含漏洞,应该对用户输入进行严格的验证和过滤,并采取适当的安全措施来限制对敏感文件的访问。
文件包含漏洞示例
可以根据不同的编程语言和框架有所不同,但这里我将给出一个基于PHP的本地文件包含(Local File Inclusion,LFI)漏洞的示例。假设有一个简单的PHP应用程序,它使用include
函数来动态地包含用户指定的文件。应用程序的代码如下所示:
<?php
// 假设用户输入的文件名存储在$_GET['file']变量中
$file = $_GET['file'];
// 尝试包含用户指定的文件
include($file);
?>
在上述代码中,$file
变量直接接收了来自URL查询字符串的file
参数,并且没有任何验证或过滤就直接被用在了include
函数中。这就构成了一个严重的文件包含漏洞。
攻击者可以利用这个漏洞来包含并执行服务器上的任意文件。例如,如果服务器上有一个名为config.php
的文件,它包含了数据库的用户名和密码等敏感信息,攻击者可以通过构造以下URL来访问这个文件:
http://example.com/vulnerable_script.php?file=config.php
当应用程序接收到这个URL请求时,它会尝试包含并执行config.php
文件,从而泄露了敏感信息。
除了包含现有的文件之外,攻击者还可以尝试包含其他恶意文件或利用文件路径遍历等技术来访问服务器上的其他目录和文件。例如,如果服务器上的目录结构允许,攻击者可能会尝试包含/etc/passwd
文件(在Unix/Linux系统上)来查看系统用户列表。
为了修复这个漏洞,开发人员应该对用户输入的文件名进行严格的验证和过滤。例如,可以只允许包含特定的文件或目录,或者对文件名进行白名单验证,确保它只包含预期的字符和格式。此外,还可以使用文件路径的绝对路径,而不是相对路径,来减少目录遍历攻击的风险。
在PHP中,一个更安全的方式来包含文件是使用include_once
或require_once
函数,并确保文件路径是硬编码的或来自可信的源。同时,使用安全的文件路径和文件名替换变量,可以进一步减少文件包含漏洞的风险。
在PHP中,常用的文件包含函数主要有两个:include
和 require
。这两个函数都用于在当前位置插入并执行指定的文件。然而,它们在处理文件不存在的错误时有所不同。
include()
include()
函数用于包含并运行指定文件。如果文件不存在,PHP会发出一个警告(E_WARNING),但脚本会继续执行。include()
函数通常用于包含那些不是必需的,但可能会用到的代码。
require()
require()
函数和 include()
类似,也用于包含并运行指定文件。但是,如果文件不存在,PHP会发出一个致命错误(E_COMPILE_ERROR),并停止脚本的执行。因此,require()
通常用于包含那些对于脚本执行至关重要的文件。
除了这两个基本函数外,PHP还提供了它们的变种,这些变种在包含文件之前会检查文件是否已经被包含过:
include_once()
include_once()
函数和 include()
函数的功能类似,但它会检查指定的文件是否已经被包含过。如果是,则不会再次包含。这有助于防止重复包含同一文件导致的错误。
require_once()
require_once()
函数和 require()
函数的功能类似,但它也会检查指定的文件是否已经被包含过。如果是,则不会再次包含。这同样有助于防止重复包含同一文件导致的错误。
在使用这些文件包含函数时,需要注意路径问题。你可以使用相对路径或绝对路径来指定要包含的文件。相对路径是相对于当前执行脚本的路径,而绝对路径则是从文件系统的根目录开始的完整路径。
为了安全起见,当包含用户提供的文件时,应该始终验证和过滤用户输入,以防止文件包含漏洞(Local File Inclusion, LFI)的发生。避免直接使用用户输入作为文件名或路径,而是使用白名单或预定义的路径和文件名。
开始实操
打开我们的靶场,并把难度改为low
注意get传参可以写一个不存在的文件来爆出绝对路径
利用该代码,我们可以读取一些系统本地的敏感信息
通过./表示当前位置路径,…/表示上一级路径位置,在linux中同样适用。
一些常见的敏感目录信息路径:
Windows系统:
C:\boot.ini #查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml # IIS配置文件
C:\windows\repair\sam # 存储Windows系统初次安装的密码
C:\ProgramFiles\mysql\my.ini #Mysql配置
C:\ProgramFiles\mysql\data\mysql\user.MYD #MySQL root密码
C:\windows\php.ini # php配置信息
Linux系统:
/etc/password //账户信息
/etc/shadow //账户密码信息
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
/usr/local/app/php5/lib/php.ini //PHP相关配置
/etc/httpd/conf/httpd.conf //Apache配置文件
/etc/my.conf //mysql配置文件
Medium
对http和../进行了过滤替换为空格
对于http的替换我们可以采用双写或者大小写绕过,而下面的斜杠主要是针对相对路径文件存储路径,但如果我们采用绝对路径上述过滤液可以成功绕过(双写)
High
采用file类型地址,那么我们就把我们要输入的地址进行修改
fnmatch() 函数根据指定的模式来匹配文件名或字符串。
源码中限制了文件名来防止恶意文件包含,并且!fnmatch( “file*”, $file )代码使用了fnmatch函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件,这样就无法进行远程访问。file://后面一定是绝对路径。
Impossible
采用了白名单过滤,没有漏洞。
完结撒花~