下載附件后,得到兩個檔案,一個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)
運行結果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/160090.html
標籤:其他
