攻防世界-crypto-Decode_The_File(base64隐写)

题目来源:RCTF-2015
题目描述:暂无

附件下载后,是一个文本文件,里面有658行base64编码。

原理

先将附件中每行base64编码进行解码,得到一个Python脚本。但其实信息并非隐藏在解码后的数据中,而是隐藏在编码中。首先介绍base64编码的原理,当需要编码的数据剩下1或2字节时,编码与解码过程如下:

可以看到,即使ai≠0,解码过程也能正确进行;从而可以使用ai传递一些信息。因此,只要我们将编码中的ai提取出来,就可以解出flag。

base64 隐写

关键是base64解码的时候
1.检查base64编码后面有几个等于号
2.把字符串按照base64表转换成6的倍数位数二进制
3. 删除等于号的个数*8个bit (等于号不在base64规定的范围内,只是为了补足长度,所以解码时要删除)
4.按照6个bit一组转成字符

此处的关键就是,解码的时候,会删除等于号的个数*8的bit,且我们只用6个bit表示一个等于号(xxxxxx),那么意思就是我们可以控制 等于号个数*2 bit的字符。

解题

实现的Python脚本如下:

from base64 import b64decode
from string import uppercase,lowercase,digits
from Crypto.Util.number import long_to_bytes

def solve():
    with open('encode','r') as f:
        codes=f.read()
    Lc=codes.split('\n')[:-1]
    base=uppercase+lowercase+digits+'+/'
    re2=[]
    for code in Lc:
        if '==' in code:
            re2.append(bin(base.find(code[-3]))[2:].rjust(6,'0')[2:])
        elif '=' in code:
            re2.append(bin(base.find(code[-2]))[2:].rjust(6,'0')[4:])
    ret=''.join(re2)
    return long_to_bytes(long(ret[:ret.rfind('1')+1],2))

if __name__=='__main__':
    print solve()

以文本文件的第二行(IyAJCQkJRG9jdW1lbnRhdGlvbgkJCQkgICAgI0==)为例

我们解释re2.append(bin(base.find(code[-3]))[2:].rjust(6,'0')[2:])的意思

code[-3] 返回倒数第3个字符,就是==前面的字符,即0
base.find(code[-3]) 返回字符0在base64编码表中对应的数字52(大写字母、小写字母、数字、+、/分别对应0-63)
bin(base.find(code[-3]) 返回52对应的二进制'0b110100'
bin(base.find(code[-3]))[2:] 从字符'0b110100'中取出从第3位开始的字符,即'110100'(这一步目的是去掉前面的0b,只留下二进制数字)
bin(base.find(code[-3]))[2:].rjust(6,'0')  即将原字符串右对齐,并使用'0'填充至长度为6形成一个新字符串,这里原字符串本来就是6位所以结果还是'110100',需要注意的是,原字符串是由0-64的十进制数字进行二进制转化而来,所以原字符串的位数应该为1-6位,最高也不会超过6位
bin(base.find(code[-3]))[2:].rjust(6,'0')[2:]  从6位二进制数中取出来后4位(从第3位开始直到最后1位)
re2.append() 最后将结果 放进列表中

程序运行结果如下:

$ python solve.py
ROIS{base_GA_caN_b3_d1ffeR3nT}

参考

官方wp

https://www.cnblogs.com/coming1890/p/13540370.html

 

posted @ 2021-05-14 14:32  zhengna  阅读(407)  评论(0编辑  收藏  举报