data:// 伪协议

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;

}

}else{
highlight_file(__FILE__);
}

与前面的题相比,没有了 eval() 函数,但可通过 data:// 伪协议解决。

什么是 data:// 伪协议:

data:// 伪协议允许直接在 URI 中嵌入数据(如文本或 Base64 编码的内容),常用于动态生成数据流。

tips

URI 统一资源标识符,URI 包括 URL 和 URN,或其他特殊形式,比如此处的 data:// 伪协议。URL 通过协议、位置等标识资源;URN 仅通过名称标识资源。

人话:data:// 伪协议相当于在 data:// 后写入数据, data:// 及其后的数据会被当作文件处理。

看看实例就明白了:

1
2
3
$uri = 'data://text/plain;base64,SGVsbG8gV29ybGQh'
$data = file_get_contents($uri);
echo $data;
1
data://<MIME类型>[;charset=<编码>][;base64],<数据>
  • 核心参数:MIME类型、charset(可选)、base64(可选)、数据内容。

  • 分隔符:用分号 ; 分隔参数,逗号 , 分隔参数和数据。

  • 参数选项

    • MIME类型:指定数据的媒体类型(Multipurpose Internet Mail Extensions)。常见的MIME类型有:

      类型 示例值 说明
      文本类 text/plain 纯文本(默认值,可省略但建议显式声明)
      text/html HTML 内容
      text/css CSS 样式表
      text/javascript JavaScript 代码
      图像类 image/png PNG 图片
      image/jpeg JPEG 图片
      image/gif GIF 图片
      应用类 application/json JSON 数据
      application/xml XML 数据
      application/pdf PDF 文档
      其他 audio/mpeg MP3 音频
      video/mp4 MP4 视频
    • charset(字符编码):指定数据的字符编码(仅对文本类 MIME 类型有效)。如UTF-8 与 GBK。

    • base64:声明数据部分使用 Base64 编码(显而易见非文本类数据必须使用)。(可用于绕过过滤)

      适用场景

      • 数据包含特殊字符(如 , ; \n)。
      • 二进制数据(如图片、音频)。
    • 数据部分:实际内容,可以是明文或 Base64 编码的字符串。未启用 Base64 编码,数据按明文处理时,需对特殊字符(,/;/%)进行 URL 编码(本身作为参数、数据的分隔符)。

本题解析

1
?c=data://text/plain,<?php system("tac fla*.php")?>

就是让 data://text/plain,<?php system("tac fla*.php")?> 作为被包含的文件,它将会因为 <?php 被识别为 PHP 文件,被解析并执行。于是$flag 被赋值并回显,OK。

变体

  • 将正则表达式修改为 "/flag|php|file/i"<?php ?> 没法用,但可用短标签 <? ?> 、**短输出标签 <?= ?>**或者 Base64 编码绕过。( <? ?> 就是简化版的 <?php ?><?= ?> 用于直接输出内容,如 <?= "Hello" ?> 等价于 <?php echo "Hello"; ?> 。此外 <? ?> 仅在 PHP 配置文件 php.inishort_open_tag 选项设置为 On 时有效;<?= ?> 则无需配置即生效)

  • 将文件包含改为 include($c.".php"); 的情况(往data://数据的最后拼接了.php)。其实只有 <?php ?> 中的内容会被解析,文件中 PHP 代码以外的文本会直接回显到网页(例如,此处如果$c要执行的命令无任何返回值,则网页上只会出现.php,因为.php在 PHP 代码以外)