目录
1.题目
#task.py:
import hashlib
from secret import KEY,FLAG,MASK
assert(FLAG=="de1ctf{"+hashlib.sha256(hex(KEY)[2:].rstrip('L')).hexdigest()+"}")
assert(FLAG[7:11]=='1224')
LENGTH = 256
assert(KEY.bit_length()==LENGTH)
assert(MASK.bit_length()==LENGTH)
def pad(m):
pad_length = 8 - len(m)
return pad_length*'0'+m
class lfsr():
def __init__(self, init, mask, length):
self.init = init
self.mask = mask
self.lengthmask = 2**(length+1)-1
def next(self):
nextdata = (self.init << 1) & self.lengthmask
i = self.init & self.mask & self.lengthmask
output = 0
while i != 0:
output ^= (i & 1)
i = i >> 1
nextdata ^= output
self.init = nextdata
return output
if __name__=="__main__":
l = lfsr(KEY,MASK,LENGTH)
r = ''
for i in range(63):
b = 0
for j in range(8):
b = (b<<1)+l.next()
r += pad(bin(b)[2:])
with open('output','w') as f:
f.write(r)
#output:
'''
001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010
'''
2.分析
题目考点:LFSR
题目没有给出mask和key,但是给出了一段较长的01输出序列
001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010
length = 504
而我们知道每连续的256个bit能够决定下一个bit的值,只要能够凑齐256个方程组,我们就能够求出mask,进而求出key值,所以我们可以考虑进行爆破求解,求出多个key值,然后根据断言进行选择
断言:
assert(FLAG[7:11]=='1224')
解方程组的问题可以转化为矩阵求逆的问题。把 lfsr 的状态一行一行地写在矩阵上,形成的矩阵记为 M. 把 lsfr 每次所生成的结果也拼成一个向量,记为 T. 那么掩码向量 v 使得
Mv = T
v = TM_inv
#M_inv 是M的逆矩阵,利用sagemath进行求解
3.解题
爆破mask向量
#please run the code in sagemath
import itertools
def test(padding):
s = [int(x) for x in '001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010'] + padding
M = matrix(GF(2), 256, 256)
T = vector(GF(2), 256)
for i in range(len(s) - 256):
M[i] = s[i : i + 256]
T[i] = s[i+256]
try:
v = M.inverse() * T
print(hex(int(''.join(map(str, (v))), base=2)))
except:
return
for x in itertools.product([0, 1], repeat = 8):
test(list(x))
然后完成了初步的爆破之后,我们可以利用猜测得到的输出信息(512位),以及得到的mask,进
一步求解出不确定的key,然后根据断言选择
#sagemath is needed
import itertools, hashlib, numpy as np
def bin2int(a):#将01数组转化为十进制数
return reduce(lambda x,y: x*2+y, a)
def bitAnd(a, b):#计算两个01数组中相同的1的个数
assert len(a) == len(b)
return list(map(lambda x,y: int(x)&int(y), a, b))
def test(padding):
s = [int(x) for x in '001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010'] + padding
M = matrix(GF(2), 256, 256)#定义矩阵M
T = vector(GF(2), 256)#定义向量v,用于解出掩码
for i in range(len(s) - 256):
M[i] = s[i : i + 256]#矩阵赋值
T[i] = s[i+256]#向量赋值
try:
mask = M.inverse() * T#获得掩码,凭借sagemath对矩阵的逆的求解功能进行运算
except:
return
suf = []
for i in range(256):#逐位破解
if bitAnd([0] + suf + s[0:255 - i], mask).count(1) % 2 == s[255 - i]:
suf = [0] + suf
else:
suf = [1] + suf
key = hex(bin2int(suf))[2:]
sha = hashlib.sha256(key.encode()).hexdigest()
if sha[:4] == '1224':#验算
print('de1ctf{' + sha + '}')
for x in itertools.product([0, 1], repeat = 8):#生成8个位置为0或1的数组
test(list(x))
得到flag:
de1ctf{1224473d5e349dbf2946353444d727d8fa91da3275ed3ac0dedeb7e6a9ad8619}