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
keywords:keywords:keywords: bitsctf-2017-beginners-luck
,文件头格式
,异或
ProblemProblemProblem
#!/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
AnalysisAnalysisAnalysis
主要加密函数supa_encryption(s1,s2)
,其作用就是将长度均为242424的s1
,s2
相异或
在实际加密过程中是将原图像fullhd.png
的十六进制数据分成以242424字节为一组的明文块与key
进行异或运算,当然key
是未知的;我们这里很显然就是要想办法求key
当然图像原数据长度很可能不是242424的倍数(这样就导致最后一组的数据并不是242424,在某些封装的异或函数中是不能执行的),加密脚本中提供了一个填充函数add_pad
,其实现的作用就是将不足242424位的明文块使用chr(24 - (len(message) % 24))
这样同一个字符填充至242424位
所以填充的字符ASCII码一定在000到242424之间,更重要的是很可能重复多次
由于异或的性质,密文我们已知,key
未知并且是需要求解的,那么我们可以试着寻找明文
由于明文是图像png
原数据的十六进制,所以可以找文件头格式(这是每个文件类型特有的一段十六进制数据)
PNG (png), 文件头:89 50 4E 47 文件尾:AE 42 60 82
实际上不止是这么点长度(我们当然是希望明文的长度越长越好了,直接达到242424位是最好,可以直接异或出key
,但是本题没有),自己创建一个png
图像,观察到前181818位十六进制固定
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00
因此可以推算出key
的前181818位
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])
剩余666位key
未知,起初想的是直接爆破明文,查看爆破结果是否为可见字符(因为密钥前部分是可见字符,所以猜测之后的部分也是可见字符);但是需要时间显然太长了,并且不好判断哪些可见字符结果是真实结果
又想到了填充的字符相同
那么由于最后一组明文块很大可能进行了填充,所以文件尾在密文中的实际的位置不定,但是最后一组密文块(一定是242424位长的)可以先用已知的部分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
文件即可
Solving codeSolving~codeSolving 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)