目录
1,base64stego
很神奇的base 64 加密 (在base 64 的密文中加密,还不影响原明文)
(转载于: https://www.tr0y.wang/2017/06/14/Base64steg/ 做了一定的修改)
(简要原理,ascii码是用8位二进制表示一个字符的,而base64是用6位二进制表示一个字符,将明文字符转化为二进制后再每6位划分成 一个 “字节”,然后将每个字节转化为一个字符,就变成了base64密文,而在base64的密文中加密是利用,每一段密文的最后4位二进制是不影响明文的,可以将flag转化为二进制后拆分隐藏在每一段的最后4位二进制中)
复习一下 Base64 吧
BASE64 是一种编码方式, 是一种可逆的编码方式.
编码后的数据是一个字符串, 包含的字符为: A-Za-z0-9+/
共 64 个字符:26 + 26 + 10 + 1 + 1 = 64
其实是 65 个字符, “=”是填充字符.
64 个字符需要 6 位二进制来表示, 表示成数值为 0~63.
这样, 长度为 3 个字节的数据经过 Base64 编码后就变为 4 个字节
编码
比如, 字符串”Tr0”经过 Base64 编码后变为”VHIw”
上面说的字符串长度为 3 个字节的数据位数是 8x3=24, 可以精确地分成 6x4.
如果字节数不是 3 的倍数, 则位数就不是 6 的倍数, 那么就不能精确地划分成 6 位的块.
此时, 需在原数据二进制值后面添加零, 使其字节数是 6 的倍数.
然后, 在编码后的字符串后面添加 1 个或 2 个等号”=”, 表示所添加的零值字节数.
比如, 字符串”Tr0y”经过 Base64 编码后变为”VHIweQ==”
橙色底纹就是添加的 0.
这是 Base64 编码的方式.
解码
解码就是编码的逆过程.
- 把 Base64 字符串去掉等号, 转为二进制数(VHIweQ== -> VHIweQ -> 010101000111001000110000011110010000).
- 从左到右, 8 个位一组, 多余位的扔掉, 转为对应的 ASCII 码(01010100 01110010 00110000 01111001 0000 -> 扔掉最后 4 位 -> 01010100 01110010 00110000 01111001 -> Tr0y)
base64密文中隐写原理
注意红色的 0, 我们在解码的时候将其丢弃了, 所以这里的值不会影响解码. 所以我们可以在这进行隐写.
为什么等号的那部分 0 不能用于隐写? 因为修改那里的二进制值会导致等号数量变化, 解码的第 1 步会受影响. 自然也就破坏了源字符串.
而红色部分的 0 是作为最后一个字符二进制的组成部分, 还原时只用到了最后一个字符二进制的前部分, 后面的部分就不会影响还原.
唯一的影响就是最后一个字符会变化. 如下图
如果你直接解密’VHIweQ==’与’VHIweR==’, 得到的结果都是’Tr0y’.
当然, 一行 base64 顶多能有 2 个等号, 也就是有 2*2 位的可隐写位. 所以我们得弄很多行, 才能隐藏一个字符串, 这也是为什么题目给了一大段 base64 的原因.
接下来, 把要隐藏的 flag 转为 8 位二进制, 塞进去就行了.
加密:
转载自:https://www.tr0y.wang/2017/06/14/Base64steg/
import base64
flag = 'Tr0y{Base64isF4n}' #flag
bin_str = ''.join([bin(ord(c)).replace('0b', '').zfill(8) for c in flag])
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('0.txt', 'rb') as f0, open('1.txt', 'wb') as f1: #'0.txt'是明文, '1.txt'用于存放隐写后的 base64
for line in f0.readlines():
rowstr = base64.b64encode(line.replace('\n', ''))
equalnum = rowstr.count('=')
if equalnum and len(bin_str):
offset = int('0b'+bin_str[:equalnum * 2], 2)
char = rowstr[len(rowstr) - equalnum - 1]
rowstr = rowstr.replace(char, base64chars[base64chars.index(char) + offset])
bin_str = bin_str[equalnum*2:]
f1.write(rowstr + '\n')
解密:
import base64
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('stego.txt', 'rb') as f: #stego.txt 为在base64密文中加密后的密文
flag = ''
bin_str = ''
for line in f.readlines():
stegb64 = str(line, "utf-8").strip("\n")
rowb64 = str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("\n")
offset = abs(b64chars.index(stegb64.replace('=', '')[-1]) - b64chars.index(rowb64.replace('=', '')[-1]))
equalnum = stegb64.count('=') # no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
for i in range(0, len(bin_str), 8):
print(chr(int(bin_str[i:i + 8], 2)),end='')
给出加密脚本执行结果
flag{Base_sixty_four_point_five}
2,easycap
下载下来是一个截取的流量包,用wireshark打开,先追踪流,没想到直接得到了flag:
3,Avatar
是一张图片,先用formost分离一下,没有什么东西,用stegsolve看一下也没发现什么,再放进winhex中看一下,依旧没收获,
再试其他工具,……在用outguess时分离出来了隐藏信息:
We should blow up the bridge at midnight
直接提交
4,What-is-this
解压文件,是一个没有后缀的文件,放进winhex中审查一下,发现有几个文件名,目测这是一个压缩包,把后缀给为zip后解压,
两张图片,正常思路:1,图片拼接 2,盲水印 3,各有一部分flag
先试一下 图片拼接,用stegsolve把两张图片合成一下:
直接提交
5,签到题
(本以为很简单,实际……)
将Z2dRQGdRMWZxaDBvaHRqcHRfc3d7Z2ZoZ3MjfQ== base64解密一下:ggQ@gQ1fqh0ohtjpt_sw{gfhgs#}
你以为这就结束了?提交错误
猜测{}的位置不对,进行一下栅栏密码:ggQ@gQ1fqh0ohtjpt_sw{gfhgs#}
2字一栏:gQg1q0hjts{fg#g@Qfhotp_wghs}
4字一栏:ggqht{ggQht_gsQ10jsf#@fopwh}
7字一栏:gfjggqpfQhth@0_ggossQhw#1t{}
14字一栏:gjgpQt@_gsQw1{fgqfhh0gosh#t}
就4个都提交一下试试,结果全都不对,,,,
用 ggqht{ggQht_gsQ10jsf#@fopwh} 再试一下 凯撒密码:
看到一个ctf直接提交:
ssctf{ssctf_sec10ver#@rabit}
6,Training-Stegano-1
好小的一张图片,第一反应是用winhex修改宽和高,没想到打开直接发现了flag:
提交:
steganoI
7,Excaliflag
用foremost分离没发现东西,用stegsolve看一下:
8,Get-the-key.txt
解压文件 得到一个 没有后缀的 文件 forensic100,看这个名字 我还以为是一个 截取的流量包,后缀改为 pcap 看了一下,没发现什么的,用winhex看一下,猜测是一个压缩包,后缀改为 zip
解压得到 key.txt:
SECCON{@]NL7n+-s75FrET]vU=7Z}
9,glance-50
打开是一个极窄的git图片,那还还用想吗?思路肯定是,先把动态图的每一帧分离出来,再拼接起来
上脚本:
分离:
import os
from PIL import Image
def seoaration_gif(gif_file):
png_dir = gif_file[:-4] + '/'
os.mkdir(png_dir)
img = Image.open(gif_file)
try:
while True:
current = img.tell()
img.save(png_dir+str(current)+'.png')
img.seek(current+1)
except:
pass
if __name__=='__main__':
gif_fil