尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

PHP伪协议在CTF文件包含漏洞中的实战利用与绕过技巧

PHP伪协议在CTF文件包含漏洞中的实战利用与绕过技巧
📅 发布时间:2026/7/27 22:29:13

1. 项目概述:从“包含”到“掌控”的思维跃迁

刚接触CTF(Capture The Flag,夺旗赛)Web安全方向的新手,常常会在“文件包含漏洞”这类题目面前卡壳。题目描述可能很简单,比如一个形如?page=about.php的链接,提示你“找到藏在服务器上的flag”。你试了试?page=../../etc/passwd,发现不行;又试了试绝对路径,还是被拦截。这时候,一股挫败感就上来了。其实,很多情况下,突破口并不在于你能否猜到flag文件的绝对路径,而在于你是否理解服务器处理“包含”这个动作时的底层逻辑。PHP伪协议,正是打开这扇逻辑之门的万能钥匙。它允许你将一个“文件路径”的请求,转化为对数据流、压缩包、甚至PHP自身输入输出的操作。这篇文章,我就以一个老CTF玩家的视角,带你彻底搞懂如何利用PHP伪协议来绕过文件包含漏洞的各种限制,最终拿到Flag。我会结合具体的实战场景和截图,让你不仅知道怎么用,更明白为什么能用,以及在不同限制条件下该如何变通。

2. 核心原理:PHP伪协议为何能成为“漏洞放大器”

在深入实操之前,我们必须先建立正确的认知:文件包含漏洞本身,只是提供了一个“将外部数据作为代码执行或内容读取”的可能性。而PHP伪协议,则极大地扩展了“外部数据”的来源和形式。你可以把它想象成一个多功能转换插头,服务器本来只想让你插U盘(包含本地文件),但这个插头却能让你接上移动硬盘、网络存储、甚至把一段文本直接变成虚拟文件。

2.1 文件包含漏洞的本质

PHP中,include、require、include_once、require_once这些函数,其设计初衷是为了代码复用。比如,你把数据库连接代码写在config.php里,然后在其他页面通过include(‘config.php’)来引入。漏洞的产生,是因为这个“被包含的文件名”是一个变量,而这个变量来自于用户可控的输入(如GET参数?file=)。如果程序没有对这个输入进行严格的过滤(比如检查是否包含../, 是否以.php结尾等),攻击者就可以操纵这个变量,去包含服务器上的任意文件。

关键点:包含函数会将被包含文件的内容,在当前作用域内“执行”(如果是PHP代码)或“输出”(如果是文本)。这意味着,如果你能包含一个存储了PHP代码的日志文件,或者一个你上传的图片马(图片中包含PHP代码),那么这些代码就会被执行。

2.2 PHP伪协议的角色

PHP内置了多种封装协议,用于访问不同的输入/输出流。在文件包含的语境下,我们关注的是那些能“读取数据”的协议。它们改变了“包含”的源:

  • 传统包含:include(‘/var/www/html/secret.txt’)-> 从文件系统读取secret.txt的内容。
  • 伪协议包含:include(‘php://filter/read=convert.base64-encode/resource=secret.txt’)-> 通过php://filter这个“过滤器”流,读取secret.txt的内容,并先进行base64编码。

伪协议的核心优势在于绕过路径限制和进行数据转换。很多CTF题目会禁止目录穿越(../),或者要求被包含的文件必须以.php结尾。这时,直接的文件路径包含就失效了。但伪协议提供了一种“间接”访问文件的方式,它描述的“资源”依然是一个文件路径,但协议处理器可能会以不同的方式解析它,从而绕过一些简单的黑名单过滤。

注意:伪协议的使用需要对应的PHP配置支持。例如,allow_url_fopen和allow_url_include这两个配置会影响php://input和http://等协议的使用。在CTF环境中,出于考察目的,这些配置常常是开启的,但在实际渗透测试中,需要先进行探测。

3. 常用PHP伪协议详解与实战场景

下面我们逐一拆解在CTF文件包含题中最常遇到的几种伪协议,我会用具体的代码片段和假设的题目场景来说明。

3.1 php://filter —— 读取文件内容的“瑞士军刀”

这是最常用、最强大的伪协议,主要用于读取任意文件的源代码,特别是在无法直接输出文件内容(比如服务器配置了不显示PHP代码)或需要绕过某些过滤时。

基本语法:php://filter/read=<过滤器链>/resource=<要读取的文件>php://filter/write=<过滤器链>/resource=<要写入的文件>

核心过滤器:

  • convert.base64-encode&convert.base64-decode: 进行base64编解码。这是最重要的过滤器,用于将文件内容以base64格式输出,避免内容被直接执行或特殊字符被浏览器解释导致显示不全。
  • string.rot13: 进行ROT13编码。
  • string.toupper/string.tolower: 转换大小写。
  • zlib.deflate/zlib.inflate: 进行压缩/解压。

实战场景1:读取本地系统文件(如/etc/passwd)假设题目URL为:http://ctf.example.com/?file=welcome.php我们尝试读取/etc/passwd。

  • 直接包含:?file=../../../../etc/passwd(可能被过滤)
  • 使用filter协议:?file=php://filter/read=convert.base64-encode/resource=/etc/passwd
  • 提交后,页面可能会显示一串base64编码的字符串,如cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaAo...
  • 我们将这串字符复制下来,使用在线工具或命令行echo “cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaAo...” | base64 -d进行解码,即可看到/etc/passwd的明文内容。

(示意图:页面显示为一长串杂乱字符,实为base64)

实战场景2:读取网站源码(获取数据库密码或flag路径)这是CTF中的高频考点。题目可能包含了一个index.php,但flag藏在config.php或flag.php里。直接访问config.php可能返回空白或错误,因为PHP代码被执行了而非显示。

  • 利用filter读取:?file=php://filter/read=convert.base64-encode/resource=config.php
  • 解码后,你就能看到config.php的完整源代码,其中可能包含类似$flag = “flag{this_is_real_flag}”;或数据库连接信息$db_pass = “secret123”;的关键内容。

实操心得:

  • 为什么一定要用base64编码?因为如果直接包含resource=config.php,其中的PHP代码(如<?php $flag=... ?>)会被服务器执行,执行结果(可能什么都没有)会输出到页面,你看不到源代码。而base64编码后,PHP引擎将其视为一段文本数据而非代码,原样输出编码后的字符串,我们解码即可得源码。
  • 多层过滤器链:你可以组合多个过滤器,例如先rot13再base64:read=string.rot13|convert.base64-encode/resource=config.php。这在某些简单的过滤器绕过题中可能会用到。

3.2 php://input —— 执行任意代码的“后门”

这个协议允许你访问请求的原始数据(即POST Body)。当allow_url_include设置为On时,你可以通过它来包含POST数据中的PHP代码并执行。

基本语法:php://input

实战场景:绕过文件后缀限制题目代码可能如下:

<?php $file = $_GET[‘file’]; if (strpos($file, ‘.php’) !== false) { // 检查参数是否包含.php include($file . ‘.php’); // 安全地添加后缀?不! } else { include($file); } ?>

看起来它强制了.php后缀。但我们可以利用php://input。

  1. 使用GET参数传入协议:?file=php://input
  2. 同时,将HTTP请求方法改为POST,并在POST Body中写入要执行的PHP代码:<?php system(‘ls /’); ?>
  3. 发送请求后,服务器会执行include(‘php://input’),而php://input流的内容就是我们POST的system(‘ls /’)代码,这段代码会被执行,并将根目录列表返回给我们。

(示意图:Burp Repeater标签页,GET参数file=php://input,下方Request Body为<?php system(‘ls’);?>)

注意事项:

  • 这个方法极其危险,因为它相当于一个远程代码执行(RCE)漏洞。在CTF中,一旦发现allow_url_include=On且存在文件包含点,应优先尝试此方法。
  • 请求的Content-Type无需特殊指定,但务必确保是POST请求。
  • 代码执行后的输出会直接嵌入到包含点的页面中。

3.3 data:// —— 将文本直接变为可执行文件

data://协议类似于php://input,但它允许直接将一段编码后的数据作为文件内容进行包含。它通常用于需要一次性提供数据和协议的场景,无需发起两次请求(如GET+POST)。

基本语法:data://<MIME类型>;base64,<base64编码的数据>或data://<MIME类型>,<URL编码的数据>

实战场景:在GET请求中直接执行代码题目可能过滤了php://或不允许POST请求。

  • 构造Payload:?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==
  • 其中,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==是<?php system(‘cat /flag’);?>的base64编码。
  • 服务器包含这个“文件”时,实际上包含的是我们提供的base64解码后的PHP代码,从而执行cat /flag命令。

与php://input的对比:

  • data://更便捷,一个GET请求即可完成,适合在浏览器地址栏直接操作或用于某些限制POST的场合。
  • php://input更灵活,可以发送更大量、更复杂的POST数据。
  • 两者都需要allow_url_include=On。在实际CTF中,如果php://input被禁用,可以尝试data://,反之亦然。

3.4 zip:// 与 phar:// —— 压缩包内的文件包含

这两个协议用于访问压缩包(ZIP或PHAR)内的特定文件。这在“上传图片马但无法直接访问”或“需要包含特定路径下文件”的场景中非常有用。

基本语法:

  • zip://<压缩包文件绝对路径>#<压缩包内文件路径>
  • phar://<压缩包文件绝对路径>/<压缩包内文件路径>

注意:zip://中的路径需要使用绝对路径,且#需要URL编码为%23。phar://则相对宽松。

实战场景:绕过文件上传限制题目允许上传图片(.jpg),后端会检查文件头。你制作了一个包含一句话PHP代码的shell.php,然后将其压缩为shell.zip,再将shell.zip重命名为shell.jpg上传。服务器保存路径为/uploads/abc123.jpg。

  1. 找到文件包含点:?file=xxx
  2. 构造Payload:?file=zip:///var/www/html/uploads/abc123.jpg%23shell.php
    • /var/www/html/uploads/abc123.jpg是上传文件的绝对路径(需要猜测或通过报错等信息获取)。
    • %23是#的URL编码。
    • shell.php是压缩包内的文件名。
  3. 服务器会解压这个“图片”,读取其中的shell.php并执行。

实操心得:

  • 绝对路径的获取:这是使用zip://和phar://的最大难点。可以通过报错信息、读取/proc/self/cwd符号链接、或利用其他漏洞(如目录遍历)来获取Web根目录的绝对路径。
  • phar的通用性:phar://协议功能更强,不仅可以包含ZIP,还能包含PHAR、TAR等格式,且对路径格式要求更友好。在不确定的情况下,可以优先尝试phar://。
  • 利用姿势扩展:甚至可以不需要文件上传,如果存在一个已知的ZIP文件在服务器上(比如website.zip备份),也可以尝试包含其中的文件。

4. 实战解题流程与技巧汇编

掌握了协议,还需要一套系统的解题流程。下面我以一个虚构的、综合性的CTF题目为例,展示完整的解题思路。

题目描述:访问http://靶机IP/,显示一个页面,有一个链接 “View some pages”,点击后URL变为http://靶机IP/?page=about.html。尝试发现?page=../../etc/passwd被拦截,页面返回 “Hacker!”。

4.1 第一步:信息收集与漏洞确认

  1. 探测包含点:尝试?page=index.php、?page=./index.php,观察页面是否正常包含,确认page参数确实用于文件包含。
  2. 探测过滤规则:
    • 尝试?page=....//....//etc/passwd(双写绕过):失败。
    • 尝试?page=/etc/passwd(绝对路径):失败。
    • 尝试?page=php://filter/read=convert.base64-encode/resource=index.php:成功!页面返回base64编码后的index.php源码。这说明服务器没有过滤php://协议,且allow_url_fopen是开启的。
    • 解码index.php源码,分析其逻辑。

4.2 第二步:源码审计与寻找flag线索

解码得到的index.php关键部分可能如下:

<?php $page = $_GET[‘page’] ?? ‘home.html’; $safe_page = str_replace(‘../’, ‘’, $page); // 简单过滤目录穿越 if (strpos($safe_page, ‘flag’) !== false) { // 禁止路径中出现flag字符串 die(‘Not allowed!’); } include(‘./pages/’ . $safe_page); ?>

分析:

  • 过滤了../,但只过滤一次,双写绕过可能有效?但之前试过失败了,可能过滤了多次或用了其他方法。
  • 过滤了路径中的flag字符串。
  • 包含路径被限定在./pages/目录下。

4.3 第三步:利用伪协议构造Payload

目标:读取可能存在的flag.php或flag.txt。

  1. 尝试直接读取:?page=php://filter/read=convert.base64-encode/resource=flag.php-> 返回 “Not allowed!”,因为路径中包含flag。
  2. 利用过滤器链绕过关键字过滤:php://filter的resource参数是最终要读取的文件。我们可以尝试对resource的值进行编码,看服务器是否在解码后才进行关键字检查。但通常检查发生在include函数处理路径之前,伪协议本身可能无法绕过这个检查。需要换个思路。
  3. 读取pages目录下的其他文件:先看看pages目录有什么。?page=php://filter/read=convert.base64-encode/resource=./pages/.(尝试读目录) -> 失败,resource必须是一个文件。
  4. 读取可能存在的配置文件:?page=php://filter/read=convert.base64-encode/resource=config.php-> 成功!解码后发现定义了$flag_path = ‘/secret_abc123/flag.txt’;。
  5. 最终读取flag:现在知道了flag的绝对路径,且该路径不经过page参数的检查。直接使用filter协议读取:?page=php://filter/read=convert.base64-encode/resource=/secret_abc123/flag.txt。解码后得到flag:flag{y0u_4r3_m4st3r_0f_php_f1lt3r}。

(示意图:浏览器或Burp中,请求上述Payload,响应为一段base64,解码后为flag{…})

4.4 第四步:进阶利用(如果上述失败)

如果config.php里没有线索,或者php://filter被禁用,我们需要考虑其他协议。

  1. 尝试php://input:将请求改为POST,?page=php://input,Body里写<?php system(‘find / -name “*flag*“ 2>/dev/null’);?>。如果成功,会列出服务器上所有包含“flag”的文件路径。
  2. 尝试data://:?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCJmaW5kIC8gLW5hbWUgXCJmbGFnKlwiIDI+L2Rldi9udWxsIik7Pz4=(即上述find命令的base64编码)。
  3. 尝试日志文件包含:如果服务器开放了错误日志,且我们知道其路径(如/var/log/apache2/access.log),可以尝试包含它。首先,我们需要将PHP代码注入到日志中。通过User-Agent头携带PHP代码访问网站:User-Agent: <?php phpinfo(); ?>。然后,包含日志文件:?page=php://filter/read=convert.base64-encode/resource=/var/log/apache2/access.log,在解码后的日志中搜索我们的请求,如果代码被原样记录,则可能被执行。这是一个非常经典的“日志投毒”技巧。

5. 常见问题、绕过技巧与防御浅谈

5.1 常见过滤与绕过方法

CTF题目和WAF(Web应用防火墙)会设置各种过滤,下面是一些常见情况:

过滤规则可能绕过方式原理与示例
过滤../双写绕过....//一次过滤后剩下../:str_replace(‘../’, ‘’, ‘....//’) -> ‘../‘
过滤php://大小写混淆PHP://、Php://PHP协议处理可能不区分大小写
过滤data://使用data://的另一种格式data:text/plain,<?php…?>(不常用)
强制添加后缀.php利用?或#截断?file=php://input%00(需要PHP<5.3.4且magic_quotes_gpc=Off) 或?file=php://filter/…/resource=/etc/passwd%00,%00空字节会截断后面的.php。注意:高版本PHP已修复。
检查文件是否存在使用php://filter和php://input这些是协议流,不是真实文件路径,file_exists()检查可能返回false,但include仍能工作。
目录限制结合伪协议使用绝对路径即使包含函数前加了目录前缀,如include(‘./pages/’. $file),使用php://filter/…/resource=/etc/passwd时,resource参数指定的绝对路径会覆盖前面的相对路径。

重要提示:空字节截断 (%00) 在PHP 5.3.4及以上版本已失效,现代CTF环境很少能用,但老题目或知识体系中仍会提及。

5.2 实操中容易踩的坑

  1. Base64解码错误:从网页复制base64字符串时,注意是否包含换行、空格或HTML标签。最好使用Burp Suite的Decoder模块或浏览器的开发者工具直接查看响应体的原始内容(Raw Response)。
  2. 绝对路径未知:这是最大的障碍。除了通过报错、读取/proc/self/environ(环境变量)、/proc/self/cwd(当前工作目录) 等文件获取,还可以尝试利用PHP的realpath函数特性或暴力猜解常见路径(如/var/www/html/,/home/www/,/usr/local/nginx/html/)。
  3. 协议被禁用:如果所有伪协议都返回错误或空白,可能是allow_url_fopen和allow_url_include被关闭。这时需要回归到传统的本地文件包含思路,比如寻找上传点、包含日志、包含/proc/self/fd/下的文件描述符等。
  4. 代码不执行:使用php://input或data://时,确保POST的代码是完整的<?php … ?>标签。有时需要尝试短标签<? … ?>或<script language=”php”>…</script>(取决于PHP配置)。

5.3 从攻击者视角看防御

理解了攻击,才能更好地防御。作为开发者,避免文件包含漏洞需做到:

  1. 白名单制度:不要使用用户输入直接作为包含的文件名。如果必须动态包含,应预先定义好允许的文件列表(白名单),只包含列表内的文件。
  2. 路径固定:将被包含的文件限制在某个特定目录下,并使用硬编码或白名单方式拼接完整路径,确保用户输入无法跳出该目录。
  3. 严格过滤:如果无法使用白名单,必须对输入进行严格过滤。不仅要过滤../,还要过滤php://,data://,zip://,phar://等协议字符串,以及空字节等特殊字符。注意过滤函数的顺序和逻辑,避免被绕过。
  4. 关闭危险配置:在生产环境中,务必在php.ini中设置allow_url_fopen = Off和allow_url_include = Off。这是最有效的一劳永逸的方法。
  5. 使用安全的函数:考虑使用file_get_contents()读取非PHP文件内容,或者使用模板引擎,彻底避免include/require的动态调用。

文件包含漏洞配合PHP伪协议,其威力远超简单的目录遍历。它模糊了“数据”与“代码”的边界,将一次本地的文件读取,升级为可能的信息泄露、代码执行甚至远程命令执行。对于CTF选手而言,熟练掌握这套组合拳,是攻克Web类题目的基本功。而对于开发者,认识到这些协议的潜在风险,则是编写安全代码的第一步。真正的安全,始于对攻击技术的深刻理解。在实战中,往往需要将多种协议、多种技巧组合使用,并耐心地进行信息收集和测试,才能从那个看似无害的?file=参数中,找到通往Flag的隐秘通道。

相关新闻

  • 2026年美国留学口碑最好的机构:五家优选权威解析 - 科技焦点
  • 德语论文辅导平台对比分析 - 逢君学术-AI论文写作
  • EmbeddingGemma-300M:轻量级嵌入模型的范式转变与边缘计算革命

最新新闻

  • Frida Stalker动态插桩实现代码覆盖率分析,赋能模糊测试与漏洞挖掘
  • 验证码安全设计误区与BurpSuite实战绕过
  • 3-L3-侦查与扫描-day11
  • 传奇电影《终结者2》约翰·康纳的笔记本电脑
  • GEO优化服务商哪家效果好?2026年五家实力厂商效果实测对比 - 纬度视角家
  • AI Agent任务拆解与记忆系统设计实践

日新闻

  • OpenClaw开源智能体网关:AI助手与即时通讯的完美融合
  • 写一个简单的sh脚本
  • 2026年 西安缝隙天线厂家:5G通信与车载天线专业定制供应商深度分析 - 卓企推荐

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号