【攻防世界】beginners-luck
给你一个加密过的图片和加密用的 py,加密过程就是用一个长度为 24 的 key 循环异或一下图片的字节流
这题与其说是密码题不如说是 misc 题
png 的前 16 位都是定死的,89 50 4e 47 0d 0a 1a 0a 是固定文件头,接下来的第一个数据块必须是关键数据块
关键数据块的组成部分:
00 00 00 0d 表示数据块长度为13 ,这个不会变
49 48 44 52 是 IHDR 标识,这个也是死的
接下来 8 位,前 4 位是宽,后 4 位是高
最后 5 位中第一位是色深,第二位是颜色类型,接下来一般都是三个 00
在关键数据块后还有 4 位 CRC 校验码
那么可以看到,前 24 位中只有宽和高的 8 位不是死的,key 的 16 位可以直接解出来
直接爆破宽高得 key 然后解密看图得方式是不可能的
不过可以发现,出题人很良心地让 key 的长度刚好到高的 4 位这里停下来,那么也就是说关键数据块的末 5 位和 CRC 校验码都是可以解的
那么就可以枚举宽高,然后快速通过 CRC 校验来验证啦
爆破代码:
1 crc = 0x67b15614 2 for i in range(0x000, 0xfff): 3 for j in range(0x000, 0xfff): 4 width = struct.pack('>i', i) 5 height = struct.pack('>i', j) 6 # print(width, height) 7 data = b'\x49\x48\x44\x52' + width + height + b'\x08\x02\x00\x00\x00' 8 crc2 = binascii.crc32(data) & 0xffffffff 9 if crc2 == crc: 10 print(width, height)
坑:
还是常见坑,python 对二进制流的处理字词得不是很好
如果你想把一个 str 转成 bytes ,最好这样:
r = b''
for i in t:
r = r + ord(i).to_bytes(1, byteorder='big')