0x01 Base64编码
0x01 简述
Base64编码是目前应用十分广泛的一种编码方式。其作用在于将非ASCII字符转换为ASCII字符进行传输,使得消息能顺利完整地从文本通道通过。
数据在传输过程中会经过许多各式各样的网关,而且不同地区的计算机使用的文本编码可能不同,其中含有的非ASCII字符可能会在传输途中发生错误,从而导致数据出错或丢失。比如电子邮件的附件中往往含有许多非ASCII字符,为了让这些数据安全地到达目的地,人们于是使用Base64对其进行编码。
0x02 原理
假设有这样一个字符串"El Psy Kongroo",我们根据其对应的ASCII码转换为二进制数。
转换后的二进制数若不满8位则用0补满。将得到的各二进制数拼接起来,再每6位划为一组,若不满6位则用0补满。
于是得到
最后将每组二进制数分别转换为十进制数,并按照编码表转换为对应的ASCII字符。
那么这个字符串对应的Base64编码结果就是
0x02 Base64隐写术
0x01 原理
我们知道,一段数据在进行Base64编码时,若最后的二进制数不满6位则需要用0补满,而在解码时这些用来填充空位的0会被舍弃,也就是说这些占位符并不会影响解码的结果。因此可以对其随意更改,解码的结果都是不变的。
再拿这个字符串为例子“El Psy Kongroo”,其二进制数最后两组补满后为111100 000000。111100在编码表中对应的字符为 ’8‘,000000对应的是 ‘=’,我们不能对000000进行修改,否则 ‘=’ 会变为其他字符。但我们可以对111100斜体的部分进行修改,修改这个二进制数的最后两位只会让编码后的结果发生改变,而不会影响复原得到的原文。
例如,将111100改为111110,整段字符串的编码结果变成了“RWwgUHN5IEtvbmdyb2+=”,而对这段新得到的字符串进行Base64解码,得到的原文仍是“El Psy Kongroo”。
111101,111111同理。
从上述操作我们可以得知,当一段Base64编码结果末尾有一个 ‘=’ 时,这段编码有2比特可以用来隐藏数据;当末尾有两个 ‘=’ 时,这段编码有4比特可以用来隐藏数据;而当末尾没有 ‘=’ 时,这段编码无法用来隐藏数据。
这里就是可以让我们隐藏数据的好地方。我们可以将一大段文字分段进行Base64编码,然后将想要隐藏的信息转换为比特流,按顺序藏在在每段末尾有 ‘=’ 的编码中。
当想要复原隐写的信息时,就需要将有 ‘=’ 的编码筛选出来并进行如下操作:如果是只有一个 ‘=’ 的编码,则提取最后一个非 ‘=’ 字符对应编码表的十进制数,将其转换为二进制并提取最后两位比特;如果是有两个 ‘=’ 的编码,则提取最后一个非 ‘=’ 字符对应Base64编码表的十进制数,将其转换为二进制并提取最后四位比特。最后,将提取出来的比特拼接,再每八位划为一组,转换为十进制数后按照ASCII码表还原出隐写的信息。
0x02 示例
本例题来自于攻防世界MISC009
题目给出一个base64.txt文件,其内容为
直接进行Base64解码得到的结果是这样一段文字
按照上一节所阐述的原理,可以写出对应的隐写复原脚本
#将字符按照Base64编码表转换为十进制数
def b64ord(char):
if char in 'abcdefghijklmnopqrstuvwxyz':
return ord(char) - 71
elif char in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
return ord(char) - 65
elif char in '0123456789':
return ord(char) + 4
elif char == '+':
return 62
elif char == '/':
return 63
else: return
with open('C:/Users/shenn/Desktop/base64.txt', 'r') as f:
ostr = f.read()
info = ''
flag = ''
count = 0
for i in ostr:
if i == '\n':
count += 1
ostr = ostr.splitlines()
for i in range(0, count):
tmp = ''
if '==' in ostr[i]:
code = b64ord(ostr[i][-3])
tmp = str(bin(code))[-4::]
#由于python会在二进制数前加上'0b',所以采取以下操作去掉
if code <= 1:
tmp = '000' + tmp[-1]
elif 2<= code <= 3:
tmp = '00' + tmp[-2::]
elif 4<= code <= 7:
tmp = '0' + tmp[-3::]
elif '=' in ostr[i]:
code = b64ord(ostr[i][-2])
tmp = str(bin(code))[-2::]
if code <= 1:
tmp = '0' + tmp[-1]
info += tmp
#将得到的结果拼接起来
for i in range(0, len(info), 8):
flag += chr(int(info[i:i+8], 2))
print(flag)
脚本运行结果为:
Base_sixty_four_point_five
至此,flag已到手。