详解 php 封装协议

概述

PHP: 支持的协议和封装协议 - Manual

  • PHP 带有很多内置 URL 风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议。

  • 各个封装协议是否能使用取决于 php.ini 里 allow_url_includeallow_url_fopen 的参数设置情况。

file:// 协议

  • php.ini 中的两个参数不敏感

  • 一般访问本地文件的时候用,最好跟绝对路径(不然会基于脚本所存在的路径进行检索)

    1
    2
    # file:// 绝对路径
    index.php?file=file://D:\ha\haha\hahaha.txt
  • 甚至在一些情况下,使用直接跟远端地址也可以触发文件包含漏洞

php:// 协议

php://input

  • 可以把 php://input php://output 理解成通用的 I/O 数据流,而这个数据流就像一个堆栈,input,output 的东西可以在需要的时候立刻被执行
  • enctype="multipart/form-data" 的时候php://input 是无效的
  • php.ini 中的 allow_url_include 参数敏感,需要为 on

具体原理

1
2
3
4
5
6
<!-- 客户端就是提交一个 POST 表单 -->
<form action="" method="POST">
    name: <input type="text" name="name" value="tom" /><br />
    age:<input type="text" name="age" value="22" /><br />
    <input type="submit" value="Submit" />
</form>
1
2
3
# 服务器端
$content = file_get_contents("php://input");
echo $content; //输出name=tom&age=22
  • 如果我们确定了存在文件包含行为,且有可能要包含的文件名是由我们的输入经过 file_get_contents 控制的,那一般我们可以在 URL 访问的参数中写上
    1
    2
    3
    index.php?file=php://
    # 然后POST包内容写上
    <?php phpinfo()?>

官方对 php://input 的说明中,反复提到环境变量$HTTP_RAW_POST_DATA ,这个变量其实和 file_get_contents(php://input) 的内容是一样的。如果要开启这个变量,需要修改配置文件,找到 always_populate_raw_post_data这个选项,设置为 On ,然后重新启动 Web 服务器,就可以了。

php://output

  • 与 input 同理
    1
    2
    3
    4
    5
    <?php
    $output = fopen("php://output", "w");
    fwrite($output, "Test-Testinggggg");
    fclose($output);
    ?>

php://filter

  • (>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式(all-in-one)的文件函数非常有用,类似 readfile()file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器

  • 因为 php://filter 也对 php.ini 中的两个参数不敏感,所以在有文件包含的时候,可以尝试在 URL 中使用如下命令

    1
    index.php?file=php://filter/read=convert.base64-encode/resource=./cmd.php
php://filter 参数 描述
resource=<要过滤的数据流> 必须项。它指定了你要筛选过滤的数据流。
read=<读链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符分隔
write=<写链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符分隔
<; 两个链的过滤器> 任何没有以 read= 或 _write=_作前缀的筛选器列表会视情况应用于读或写链。

其中不同的过滤器有
image.png

php://fd

  • (>=5.3.6)允许直接访问指定的文件描述符。例如 php://fd/3 引用了文件描述符 3

php://memory & php://temp

  • (>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是 php://memory 总是把数据储存在内存中,而 php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。临时文件位置的决定和 sys_get_temp_dir() 的方式一致。

data:// 协议

  • PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码
  • php.ini 的两个参数敏感,需要都是 on 的状态
  • 当确定有文件包含的时候,可以如下使用
    1
    2
    3
    4
    5
    # data://text/plain,
    http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>

    # data://text/plain;base64,
    http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

zip:// & bzip2:// & zlib:// 协议

  • zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx 等等
  • php.ini 中的两个参数不敏感
  • 当确定存在文件包含时,如下使用
    1
    2
    3
    4
    5
    6
    7
    8
    # zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
    http://127.0.0.1/include.php?file=zip://E:\phpStudy\phpinfo.jpg%23phpinfo.txt

    # compress.bzip2://file.bz2
    http://127.0.0.1/include.php?file=compress.bzip2://E:\phpStudy\phpinfo.bz2

    # compress.zlib://file.gz
    http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\phpinfo.gz

phar:// 协议

  • 类似与上方提到的 zip:/ 压缩协议,phar 是归档协议
  • 当确定存在文件包含时,如下使用
    1
    http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
    #待处理
    利用 phar 拓展 php 反序列化漏洞攻击面
Author

Resek4

Posted on

2022-08-21

Updated on

2023-02-26

Licensed under

Comments