题目:
from flag import flag
assert flag.startswith("flag{")
# 作用:判断字符串是否以指定字符或子字符串开头flag{
assert flag.endswith("}")
# 作用:判断字符串是否以指定字符或子字符串结尾},flag{},6个字节
assert len(flag)==25
# flag的长度为25字节,25-6=19个字节
#3<<2可以这么算,bin(3)=0b11向左移动2位变成1100,0b1100=12(十进制)
def lfsr(R,mask):
output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111'=0xffffff的二进制补码
i=(R&mask)&0xffffff #按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0
lastbit=0
while i!=0:
lastbit^=(i&1) #按位异或运算符:当两对应的二进位相异时,结果为1
i=i>>1
output^=lastbit
return (output,lastbit)
R=int(flag[5:-1],2)
mask = 0b1010011000100011100
f=open("key","ab") #以二进制追加模式打开
for i in range(12):
tmp=0
for j in range(8):
(R,out)=lfsr(R,mask)
tmp=(tmp << 1)^out #按位异或运算符:当两对应的二进位相异时,结果为1
f.write(chr(tmp)) #chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。
f.close()
不懂LFSR的看看这篇文章,看完就懂了
深入分析CTF中的LFSR类题目(一)
理解一下这幅图就明白了,原理大致是 flag的最后一位,与lastbit的前31位,通过线性关系异或,会得到lastbit的 第32位,我们已知第32位,需要求flag的最后一位。所以逆向异或关系即可求得flag的最后一位。
第一种算法 EXP:
f = flag[-1]
output = ‘?’ + key[:18]
flag[-1] =key[18] ^ output[-3] ^ output[-4] ^ output[-5] ^ output[-9] ^ output[-13] ^ output[-14] ^ output[-17]
#python3
from Crypto.Util.number import*
f = open('key.txt','rb').read()
key = bytes_to_long(f)
bin_out = bin(key)[2:].zfill(12*8)
# print(bin_out) 前19位就是key
key = '0101010100111000111'
mask = '1010011000100011100'
R = ''
tem = key
for i in range(19):
output = '?' + key[:18]
ans = int(tem[-1-i]) ^ int(output[-3]) ^ int(output[-4]) ^ int(output[-5]) ^ int(output[-9]) ^ int(output[-13]) ^ int(output[-14]) ^ int(output[-17])
R += str(ans)
key = str(ans) + key[:18]
print('flag{'+R[::-1]+'}')
第二种算法EXP:
from Crypto.Util.number import*
f = open('key.txt','rb').read()
c = bytes_to_long(f)
bin_out = bin(c)[2:].zfill(12*8) #将key文本内容转换为 2 进制数,每个字节占 8 位
R = bin_out[0:19] #前32个2进制数,化为10进制整数
mask = 0b1010011000100011100
def lfsr(R,mask):
output = (R << 1) & 0xffffffff
i=(R&mask)&0xffffffff
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
output^=lastbit
return (output,lastbit)
# 根据生成规则,初始状态最后一位拼接n-1个生成位,运算后得到第n个生成位,由于生成位已知,因此可以逆推初始状态最后一位。
# 同理,逐位往前推,可得到全部的初始状态位。
# 文件的前32位二进制数,是由seed生成的一个随机数。而且是第32个生成的随机数,而且我们能根据第32个随机数猜测第31个随机数,
# 因为第31个随机数的低31位是第32个随机数的高31位。猜测32次后可以得到原始seed,即flag
def decry():
cur = bin_out[0:19] #前19位 2 进制数
res = ''
for i in range(19):
if lfsr(int('0'+cur[0:-1],2),mask)[0] == int(cur,2):
res += '0'
cur = '0'+cur[0:-1]
else:
res += '1'
cur = '1' + cur[0:-1]
return int(res[::-1],2)
r = decry()
print(bin(r))