从‘Include’到‘Get Flag’:手把手教你用php://filter绕过CTF文件包含限制

当你第一次看到CTF题目中"Include"这个关键词时,脑海中可能会闪过"文件包含"的概念,但具体如何利用这个漏洞获取flag却让人摸不着头脑。这正是很多CTF新手在Web安全方向遇到的典型困境——知道理论却不知如何实践。本文将带你一步步拆解这个思维过程,从题目提示到最终payload构造,让你真正掌握php://filter这个强大工具的使用精髓。

1. 理解文件包含漏洞的本质

文件包含漏洞通常出现在PHP应用中,当开发者使用 include require 等函数动态加载文件时,如果未对用户输入进行严格过滤,攻击者就能通过控制文件路径参数来读取或执行任意文件。在CTF比赛中,这类题目常以"Include"为提示,引导选手发现并利用这一漏洞。

为什么直接读取flag.php不显示内容?

尝试直接访问flag.php时,你可能只看到类似"Can you find out the flag?"的提示,而看不到实际的flag内容。这是因为:

  1. PHP文件会被服务器解析执行,只输出执行结果而非源代码
  2. flag通常被定义为变量或常量,不会直接输出
  3. 题目可能设置了特殊防护,阻止直接访问敏感文件

这时就需要用到php://filter伪协议,它能让我们以各种编码方式读取文件内容,绕过这些限制。

2. php://filter伪协议详解

php://filter是PHP中一个强大的流过滤器,它允许我们对数据流进行各种处理后再输出。在文件包含漏洞利用中,它主要有以下优势:

  • 可以读取PHP文件源码而非执行结果
  • 支持多种编码转换,绕过简单过滤
  • 不需要特殊文件权限即可使用

2.1 基础payload构造

最常用的payload结构如下:

php://filter/read=convert.base64-encode/resource=目标文件

这个payload的工作原理是:

  1. php://filter :指定使用过滤器流
  2. read=convert.base64-encode :对读取内容进行base64编码
  3. resource=目标文件 :指定要读取的文件路径

实际操作示例

curl "http://example.com/?file=php://filter/read=convert.base64-encode/resource=flag.php"

执行后会返回flag.php的base64编码内容,你需要使用base64解码工具还原源代码:

import base64
encoded = "PD9waHAKJGZsYWcgPSAiZmxhZ3tleGFtcGxlfSI7Cj8+"
print(base64.b64decode(encoded).decode('utf-8'))

2.2 为什么base64编码有效

你可能会有疑问:为什么直接读取不行,而编码后就可以?这主要基于以下原因:

  1. 防止PHP解析 :base64编码后的内容不会被当作PHP代码执行
  2. 绕过输出限制 :某些防护措施可能过滤特定内容,编码后能绕过
  3. 保证数据完整性 :base64能确保特殊字符(如<、?)不被错误处理

3. 进阶技巧:多种编码方式组合

当题目对base64编码进行过滤时,我们可以尝试其他编码方式。php://filter支持丰富的编码转换功能,其中最灵活的是 convert.iconv 过滤器。

3.1 iconv编码转换

iconv是Linux下的字符集转换工具,PHP通过 convert.iconv 提供了类似功能。基本语法为:

convert.iconv.<输入编码>.<输出编码>

常用编码方式包括:

编码类型 说明
UTF-8 最常用的Unicode编码
UTF-16 双字节Unicode编码
ASCII 基础英文字符编码
UCS-4 32位统一字符编码

实用payload示例

php://filter/convert.iconv.utf8.utf16/resource=flag.php

这个payload会将文件内容从UTF-8转换为UTF-16编码,同样可以绕过PHP执行直接获取源码。

3.2 编码组合技巧

更复杂的编码组合有时能绕过更严格的过滤:

php://filter/convert.iconv.utf8.utf16|convert.iconv.utf16.ucs2/resource=flag.php

这个payload先转为UTF-16,再转为UCS-2,增加了混淆程度。

4. 实战演练:从题目到flag的全过程

让我们模拟一个CTF新手的完整解题思路:

  1. 观察题目 :题目名为"Include",提示可能存在文件包含漏洞
  2. 寻找入口点 :发现URL中有 file 参数,如 ?file=tips.php
  3. 初步尝试
    • 直接访问 ?file=flag.php → 只看到提示文本
    • 尝试 ?file=index.php → 无有用信息
  4. 使用伪协议
    • 构造 ?file=php://filter/read=convert.base64-encode/resource=flag.php
    • 获取到base64编码的flag.php内容
  5. 解码分析
    • 解码后发现flag定义: $flag = "flag{example}";
  6. 提交flag :复制完整flag字符串提交

常见错误与解决方法

  • 返回空白 :可能是路径错误,尝试相对路径( ./flag.php )或绝对路径
  • 被服务器拦截 :尝试降低请求频率,或使用不同编码方式
  • 编码无效 :检查编码名称是否正确,参考官方支持的编码列表

5. 防御措施与CTF设计思路

虽然本文重点在攻击技巧,但了解防御方法同样重要。常见的文件包含漏洞防御包括:

  1. 白名单验证 :只允许包含特定目录下的文件
  2. 参数过滤 :禁止包含协议(php://)和特殊字符
  3. 关闭危险功能 :在php.ini中设置 allow_url_include=Off

在CTF题目设计中,合理的文件包含题目应该:

  • 提供足够但不明显的提示(如"Include")
  • 设置合理的防御,引导选手思考绕过方法
  • flag位置要有一定隐蔽性,但不能完全无法猜测

6. 扩展应用:其他伪协议简介

除了php://filter,PHP还支持其他有用的伪协议:

  • php://input :读取POST原始数据,可用于代码执行
  • data:// :直接包含base64编码的数据
  • expect:// :执行系统命令(通常被禁用)

需要注意的是,这些协议在真实CTF比赛中可能被禁用或过滤,而php://filter通常是最可靠的备选方案。

在实际CTF比赛中遇到文件包含题目时,我的经验是先尝试最简单的base64编码payload,如果被过滤再逐步尝试更复杂的编码组合。记住,关键是理解每种编码转换的原理,而不是死记硬背payload。

更多推荐