zoukankan      html  css  js  c++  java
  • xctf-streamgame1

    下载附件后,得到两个文件,一个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.cnblogs.com/jane315/p/13773608.html
Copyright © 2011-2022 走看看