bitsctf-2017-beginners-luck
bitsctf-2017-beginners-luckkeywords:keywords:keywords: bitsctf-2017-beginners-luck,文件头格式,异或ProblemProblemProblem#!/usr/bin/env pythondef supa_encryption(s1, s2):res = [chr(0)]*24for i in range(len(res
bitsctf-2017-beginners-luck
k
e
y
w
o
r
d
s
:
keywords:
keywords: bitsctf-2017-beginners-luck
,文件头格式
,异或
P r o b l e m Problem Problem
#!/usr/bin/env python
def supa_encryption(s1, s2):
res = [chr(0)]*24
for i in range(len(res)):
q = ord(s1[i])
d = ord(s2[i])
k = q ^ d
res[i] = chr(k)
res = ''.join(res)
return res
def add_pad(msg):
L = 24 - len(msg)%24
msg += chr(L)*L
return msg
with open('fullhd.png','rb') as f:
data = f.read()
data = add_pad(data)
with open('key.txt') as f:
key = f.read()
enc_data = ''
for i in range(0, len(data), 24):
enc = supa_encryption(data[i:i+24], key)
enc_data += enc
with open('BITSCTFfullhd.png', 'wb') as f:
f.write(enc_data)
附件有
BITSCTFfullhd.png
A n a l y s i s Analysis Analysis
主要加密函数supa_encryption(s1,s2)
,其作用就是将长度均为
24
24
24的s1
,s2
相异或
在实际加密过程中是将原图像fullhd.png
的十六进制数据分成以
24
24
24字节为一组的明文块与key
进行异或运算,当然key
是未知的;我们这里很显然就是要想办法求key
当然图像原数据长度很可能不是
24
24
24的倍数(这样就导致最后一组的数据并不是
24
24
24,在某些封装的异或函数中是不能执行的),加密脚本中提供了一个填充函数add_pad
,其实现的作用就是将不足
24
24
24位的明文块使用chr(24 - (len(message) % 24))
这样同一个字符填充至
24
24
24位
所以填充的字符ASCII码一定在 0 0 0到 24 24 24之间,更重要的是很可能重复多次
由于异或的性质,密文我们已知,key
未知并且是需要求解的,那么我们可以试着寻找明文
由于明文是图像png
原数据的十六进制,所以可以找文件头格式(这是每个文件类型特有的一段十六进制数据)
PNG (png), 文件头:89 50 4E 47 文件尾:AE 42 60 82
实际上不止是这么点长度(我们当然是希望明文的长度越长越好了,直接达到
24
24
24位是最好,可以直接异或出key
,但是本题没有),自己创建一个png
图像,观察到前
18
18
18位十六进制固定
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00
因此可以推算出key
的前
18
18
18位
f = open("BITSCTFfullhd.png","rb")
ori_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00'
enc_data = f.read()
f.close()
# print(xor(ori_data,enc_data[:18]))
# b'rkh%QP4g0&3g46@4*%'
part_key = xor(ori_data,enc_data[:18])
剩余
6
6
6位key
未知,起初想的是直接爆破明文,查看爆破结果是否为可见字符(因为密钥前部分是可见字符,所以猜测之后的部分也是可见字符);但是需要时间显然太长了,并且不好判断哪些可见字符结果是真实结果
又想到了填充的字符相同
那么由于最后一组明文块很大可能进行了填充,所以文件尾在密文中的实际的位置不定,但是最后一组密文块(一定是
24
24
24位长的)可以先用已知的部分key
进行解密得到填充使用的字节
last_enc_data = "\x36\xC5\x2A\x45\xD3\x43\x27\x74\x23\x35\x20\x74\x27\x25\x53\x27\x39\x36\x75\x3B\x46\x5D\x30\x4F"
print(xor(last_enc_data[:len(part_key)],part_key))
# b'D\xaeB`\x82\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13'
显然填充的字符应该是\x13
,所以使用该字节与剩余的密文部分进行异或运算得到剩余的key
temp = "\x13" * 6
print(xor(last_enc_data[len(part_key):],temp))
key = part_key + xor(last_enc_data[len(part_key):],temp)
将key
与整个密文进行异或导出为png
文件即可
S o l v i n g c o d e Solving~code Solving code
from pwn import *
f = open("C:\\Users\\Menglin\\Desktop\\beginners-luck-40\\BITSCTFfullhd.png","rb")
ori_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00'
enc_data = f.read()
f.close()
# print(xor(ori_data,enc_data[:18]))
part_key = xor(ori_data,enc_data[:18])
last_enc_data = "\x36\xC5\x2A\x45\xD3\x43\x27\x74\x23\x35\x20\x74\x27\x25\x53\x27\x39\x36\x75\x3B\x46\x5D\x30\x4F"
# print(xor(last_enc_data[:len(part_key)],part_key))
temp = "\x13" * 6
# print(xor(last_enc_data[len(part_key):],temp))
key = part_key + xor(last_enc_data[len(part_key):],temp)
ori_data = xor(enc_data,key*(len(enc_data)//len(key)))
f = open("C:\\Users\\Menglin\\Desktop\\output.png","wb")
f.write(ori_data)
更多推荐
所有评论(0)