下载附件后,得到两个文件,一个key文件,一个streamgame1.py文件
key文件如下:(十六进制形式)
55 38 F7 42 C1 0D B2 C7 ED E0 24 3A
streamgame1.py如下:
1 from flag import flag 2 assert flag.startswith("flag{") 3 # 作用:判断字符串是否以指定字符或子字符串开头flag{ 4 assert flag.endswith("}") 5 # 作用:判断字符串是否以指定字符或子字符串结尾},flag{},6个字节 6 assert len(flag)==25 7 # flag的长度为25字节,25-6=19个字节 8 #3<<2可以这么算,bin(3)=0b11向左移动2位变成1100,0b1100=12(十进制) 9 def lfsr(R,mask): 10 output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111'=0xffffff的二进制补码 11 i=(R&mask)&0xffffff #按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 12 lastbit=013 while i!=0: 14 lastbit^=(i&1) #按位异或运算符:当两对应的 二进位相异时,结果为1 15 i=i>>1 16 output^=lastbit 17 return (output,lastbit) 18 19 20 21 R=int(flag[5:-1],2) 22 mask = 0b1010011000100011100 23 24 f=open("key","ab") #以二进制追加模式打开 25 for i in range(12): 26 tmp=0 27 for j in range(8): 28 (R,out)=lfsr(R,mask) 29 tmp=(tmp << 1)^out #按位异或运算符:当两对应的二进位相异时,结果为1 30 f.write(chr(tmp)) #chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。 31 f.close()
这里给出两种做法,第一种直接爆破得出,第二种破解程序的算法得出。
方法①:通过py文件,可以知道flag{}内的字符个数为19个,且为2进制,因此将其转换为十进制,一定不超过2**19,脚本如下:
1 from Crypto.Util.number import * 2 a="55 38 F7 42 C1 0D B2 C7 ED E0 24 3A" 3 a=a.split() 4 print(a) 5 def lfsr(R,mask): 6 output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111'=0xffffff的二进制补码 7 i=(R&mask)&0xffffff #按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 8 lastbit=0#奇偶数 9 while i!=0: 10 lastbit^=(i&1) #按位异或运算符:当两对应的 二进位相异时,结果为1 11 i=i>>1 12 output^=lastbit#最低为就是R中最后一位之前的1的奇偶数 13 return (output,lastbit) 14 15 mask = 0b1010011000100011100 16 for R in range(2**19): 17 index=1 18 #print("R:",R) 19 temp=R 20 for i in range(12): 21 tmp=0 22 for j in range(8): 23 (R,out)=lfsr(R,mask) 24 tmp=(tmp << 1)^out #按位异或运算符:当两对应的二进位相异时,结果为1 25 if tmp!=int(a[i],16): 26 index=0 27 break 28 if (index==1): 29 print("yes!!!") 30 print(temp) 31 break
运行结果:
所以flag即为flag{1110101100001101011}
方法②:
代码的大致逻辑入下:
①函数lfsr中,输出的output是R左移一位后,并且第一位(从右往左数)^lastbit的结果,而lastbite代表的是R与mask相异或后,用二进制表示的结果中1的奇偶数,1代表有奇数个1,0代表有偶数个
②函数的两个for循环中,这两个循环大致为将R不断的经过lsfr操作,每经过一次,R更新一次值,tmp的每一位代表输入的R中与mask异或的奇偶数(8个一组,写入key中)
这里的特殊性就在于,假设正在进行第19次lsfr操作,那么此时二进制R的0~18(从右往左数)为即为key[0:18],且R的最后一位为flag[0],而此次lsfr操作的输出我们已知,即output=key,lastbit=key[18],那么就可以求出R的最后一位,即flag[0]的值,往后以次类推
这里推荐两个博客,写的超详细!容易理解!
https://www.cnblogs.com/coming1890/p/13592014.html
https://www.anquanke.com/post/id/181811#h2-0
最后写出脚本如下:
1 mask = '1010011000100011100' 2 key='010101010011100011110111'[0:19]#十六进制表示为0x5538f7 3 print("key:",key) 4 5 R = '' 6 for i in range(19): 7 output = '?' + key[:18] 8 ans = int(key[-1])^int(output[-3])^int(output[-4])^int(output[-5])^int(output[-9])^int(output[-13])^int(output[-14])^int(output[-17]) 9 R += str(ans) 10 print("R:",R) 11 key = str(ans) + key[:18] 12 13 print((R[::-1])) 14 R = (R[::-1]) 15 flag = "flag{" + R + "}" 16 print(flag)
运行结果如下: