# 提取伪随机数 defextract_number(self): if self.mti == 0: self.twist() y = self.mt[self.mti] y = y ^ y >> 11 y = y ^ y << 7 & 2636928640 y = y ^ y << 15 & 4022730752 y = y ^ y >> 18 self.mti = (self.mti + 1) % 624 return _int32(y)
o = 2080737669 y = o ^ o << 15 & 4022730752 tmp = y for i inrange(32 // 15): # (y<<15)&40022730752 每次可以恢复y的15位 y = tmp ^ y << 15 & 4022730752 print(y==o)
# right shift inverse definverse_right(res, shift, bits=32): tmp = res for i inrange(bits // shift): tmp = res ^ tmp >> shift return tmp
# right shift with mask inverse definverse_right_mask(res, shift, mask, bits=32): tmp = res for i inrange(bits // shift): tmp = res ^ tmp >> shift & mask return tmp
# left shift inverse definverse_left(res, shift, bits=32): tmp = res for i inrange(bits // shift): tmp = res ^ tmp << shift return tmp
# left shift with mask inverse definverse_left_mask(res, shift, mask, bits=32): tmp = res for i inrange(bits // shift): tmp = res ^ tmp << shift & mask return tmp
defextract_number(y): y = y ^ y >> 11 y = y ^ y << 7 & 2636928640 y = y ^ y << 15 & 4022730752 y = y ^ y >> 18 return y&0xffffffff
defrecover(y): y = inverse_right(y,18) y = inverse_left_mask(y,15,4022730752) y = inverse_left_mask(y,7,2636928640) y = inverse_right(y,11) return y&0xffffffff
# sagemath 9.0 from sage.allimport * from random import Random
defbuildT(): rng = Random() T = matrix(GF(2),32,32) for i inrange(32): s = [0]*624 # 构造特殊的state s[0] = 1<<(31-i) rng.setstate((3,tuple(s+[0]),None)) tmp = rng.getrandbits(32) # 获取T矩阵的每一行 row = vector(GF(2),[int(x) for x inbin(tmp)[2:].zfill(32)]) T[i] = row return T
defreverse(T,leak): Z = vector(GF(2),[int(x) for x inbin(leak)[2:].zfill(32)]) X = T.solve_left(Z) state = int(''.join([str(i) for i in X]),2) return state
deftest(): rng = Random() # 泄露信息 leak = [rng.getrandbits(32) for i inrange(32)] originState = [i for i in rng.getstate()[1][:32]] # 构造矩阵T T = buildT() recoverState = [reverse(T,i) for i in leak] print(recoverState==originState)
definvert_right(m,l,val=''): length = 32 mx = 0xffffffff if val == '': val = mx i,res = 0,0 while i*l<length: mask = (mx<<(length-l)&mx)>>i*l tmp = m & mask m = m^tmp>>l&val res += tmp i += 1 return res
definvert_left(m,l,val): length = 32 mx = 0xffffffff i,res = 0,0 while i*l < length: mask = (mx>>(length-l)&mx)<<i*l tmp = m & mask m ^= tmp<<l&val res |= tmp i += 1 return res
definvert_temper(m): m = invert_right(m,18) m = invert_left(m,15,4022730752) m = invert_left(m,7,2636928640) m = invert_right(m,11) return m
defclone_mt(record): state = [invert_temper(i) for i in record] gen = Random() gen.setstate((3,tuple(state+[0]),None)) return gen
f = open("random",'r').readlines() prng = [] for i in f: i = i.strip('n') prng.append(int(i))
g = clone_mt(prng[:624]) for i inrange(700): g.getrandbits(32)
defbacktrace(cur): high = 0x80000000 low = 0x7fffffff mask = 0x9908b0df state = cur for i inrange(623,-1,-1): tmp = state[i]^state[(i+397)%624] # recover Y,tmp = Y if tmp & high == high: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 # recover highest bit res = tmp&high # recover other 31 bits,when i =0,it just use the method again it so beautiful!!!! tmp = state[i-1]^state[(i+396)%624] # recover Y,tmp = Y if tmp & high == high: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 res |= (tmp)&low state[i] = res return state
2020 V&N 招新赛 Backtrace
1 2 3 4 5 6 7
# !/usr/bin/env/python3 import random flag = "flag{" + ''.join(str(random.getrandbits(32)) for _ inrange(4)) + "}" withopen('output.txt', 'w') as f: for i inrange(1000): f.write(str(random.getrandbits(32)) + "n") print(flag)
#!/usr/bin/python3 from random import Random # right shift inverse definverse_right(res,shift,bits=32): tmp = res for i inrange(bits//shift): tmp = res ^ tmp >> shift return tmp # right shift with mask inverse definverse_right_values(res,shift,mask,bits=32): tmp = res for i inrange(bits//shift): tmp = res ^ tmp>>shift & mask return tmp # left shift inverse definverse_left(res,shift,bits=32): tmp = res for i inrange(bits//shift): tmp = res ^ tmp << shift return tmp # left shift with mask inverse definverse_left_values(res,shift,mask,bits=32): tmp = res for i inrange(bits//shift): tmp = res ^ tmp << shift & mask return tmp
defbacktrace(cur): high = 0x80000000 low = 0x7fffffff mask = 0x9908b0df state = cur for i inrange(3,-1,-1): tmp = state[i+624]^state[i+397] # recover Y,tmp = Y if tmp & high == high: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 # recover highest bit res = tmp&high # recover other 31 bits,when i =0,it just use the method again it so beautiful!!!! tmp = state[i-1+624]^state[i+396] # recover Y,tmp = Y if tmp & high == high: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 res |= (tmp)&low state[i] = res return state
defrecover_state(out): state = [] for i in out: i = inverse_right(i,18) i = inverse_left_values(i,15,0xefc60000) i = inverse_left_values(i,7,0x9d2c5680) i = inverse_right(i,11) state.append(i) return state
f = open("output.txt","r").readlines() c = [] for i inrange(1000): c.append(int(f[i].strip()))
partS = recover_state(c) state = backtrace([0]*4+partS)[:624] # print(state) prng = Random() prng.setstate((3,tuple(state+[0]),None)) flag = "flag{" + ''.join(str(prng.getrandbits(32)) for _ inrange(4)) + "}" print(flag)
#! /bin/bash/env python3 from sage.allimport * from random import Random from tqdm import tqdm prng = Random() length = 19968 defmyState(): state = [0]*624 i = 0 while i<length: ind = i//32 expont = i%32 state[ind] = 1<<(31-expont) s = (3,tuple(state+[0]),None) yield s state[ind] = 0 i += 1
defgetRow(): rng = Random() gs = myState() for i inrange(length): s = next(gs) rng.setstate(s) # print(s[1][0]) row = vector(GF(2),[rng.getrandbits(1) for j inrange(length)]) yield row
defbuildBox(): b = matrix(GF(2),length,length) rg = getRow() for i in tqdm(range(length)): b[i] = next(rg) return b
deftest(): prng = Random() originState = prng.getstate() # 这里都是用的MSB,如果采用不同的二进制位(如LSB)最后的矩阵T 也会不同 leak = vector(GF(2),[prng.getrandbits(1) for i inrange(length)]) b = buildBox() f = open("Matrix","w") for i inrange(b.nrows()): for j inrange(b.ncols()): f.write(str(b[i,j])+"n") f.close() x = b.solve_left(leak) x = ''.join([str(i) for i in x]) state = [] for i inrange(624): tmp = int(x[i*32:(i+1)*32],2) state.append(tmp) prng.setstate(originState) prng.getrandbits(1) originState = [x for x in prng.getstate()[1][:-1]] print(originState[1:] == state[1:]) # print(state) return state,b test()
from sage.allimport * from random import Random from tqdm import tqdm # 根据文件中的信息,构造矩阵 defbuildMatrix(): length = 19968 cnt = 0 m = matrix(GF(2), length, length) for line in tqdm(open("Matrix", "r")): row = cnt // 19968 col = cnt % 19968 m[row, col] = int(line.strip('n')) cnt += 1 return m
m = buildMatrix()
# X = Z*(T^-1) defrecoverState(leak): x = m.solve_left(leak) x = ''.join([str(i) for i in x]) state = [] for i inrange(624): tmp = int(x[i * 32:(i + 1) * 32], 2) state.append(tmp) return state
defpwn(leak): state = recoverState(leak) L = [leak[i] for i inrange(100)] prng = Random() guess1, guess2 = backfirst(state) print(guess1, guess2) state[0] = guess1 s = state prng.setstate((3, tuple(s + [0]), None)) g1 = [prng.getrandbits(1) for i inrange(100)] if g1 == L: print("first") prng.setstate((3, tuple(s + [0]), None)) return prng
state[0] = guess2 s = state prng.setstate((3, tuple(s + [0]), None)) g2 = [prng.getrandbits(1) for i inrange(100)] if g2 == L: print("second") prng.setstate((3, tuple(s + [0]), None)) return prng
deftest(): length = 19968 prng = Random() originState = prng.getstate() leak = vector(GF(2), [prng.getrandbits(1) for i inrange(length)]) # 恢复state state = recoverState(leak) prng.setstate(originState) prng.getrandbits(1) originState = [x for x in prng.getstate()[1][:-1]] # 成功恢复623个state print(originState[1:] == state[1:]) # 获取泄露信息 L = [leak[i] for i inrange(100)] # 两种可能 guess1, guess2 = backfirst(state) print(guess1, guess2) state[0] = guess1 s = state prng.setstate((3, tuple(s + [0]), None)) g1 = [prng.getrandbits(1) for i inrange(100)] if g1 == L: print("first") prng.setstate((3, tuple(s + [0]), None)) now = vector(GF(2), [prng.getrandbits(1) for i inrange(length)]) if now == leak: print("true") return state[0] = guess2 s = state prng.setstate((3, tuple(s + [0]), None)) g2 = [prng.getrandbits(1) for i inrange(100)] if g2 == L: print("second") prng.setstate((3, tuple(s + [0]), None)) now = vector(GF(2), [prng.getrandbits(1) for i inrange(length)]) if now == leak: print("true") return test()