BUUCTF [GKCTF 2021]Random
关于MT19937的攻击
32位的MT19937python代码:
def _int32(x):
return int(0xFFFFFFFF & x)
class MT19937:
# 根据seed初始化624的state
def __init__(self, seed):
self.mt = [0] * 624
self.mt[0] = seed
self.mti = 0
for i in range(1, 624):
self.mt[i] = _int32(1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)
# 提取伪随机数
def extract_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)
# 对状态进行旋转
def twist(self):
for i in range(0, 624):
y = _int32((self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff))
self.mt[i] = (y >> 1) ^ self.mt[(i + 397) % 624]
if y % 2 != 0:
self.mt[i] = self.mt[i] ^ 0x9908b0df
可以看出它一个大循环是以624为周期的
而观察题目给我们的源码
import random
from hashlib import md5
def get_mask():
file = open("random.txt","w")
for i in range(104):
file.write(str(random.getrandbits(32))+"\n")
file.write(str(random.getrandbits(64))+"\n")
file.write(str(random.getrandbits(96))+"\n")
file.close()
get_mask()
flag = md5(str(random.getrandbits(32)).encode()).hexdigest()
print(flag)
104x(1+2+3)正好=624
所以题目相当于给了我们一个完整的随机数生成块 我们可以利用RandCrack库进行预测
注意!64位 96位 这些都是由 2 3个32位拼接的 是从低位往高位拼接 注意顺序(否则会影响预测)
from hashlib import *
from randcrack import *
with open(r'\random.txt','r+') as f:
lines = f.readlines()
num = []
for line in lines:
line = int(line.strip())
num.append(line)
_random = []
for i in range(len(num)):
if i%3 == 0:
_random.append(num[i])
elif i%3 == 1:
n = num[i]
n1 = n & ((1<<32)-1)
n2 = n >> 32
_random.append(n1)
_random.append(n2)
else:
n = num[i]
n1 = n & ((1 << 32)-1)
n2 = (n >> 32) & ((1 << 32)-1)
n3 = n >> 64
_random.append(n1)
_random.append(n2)
_random.append(n3)
Rc = RandCrack()
for n in _random:
Rc.submit(n)
flag = Rc.predict_getrandbits(32)
print(md5(str(flag).encode()).hexdigest())
最后得到flag:14c71fec812b754b2061a35a4f6d8421
补 用mt19937predictor
from mt19937predictor import *
pre = MT19937Predictor()
data = open(r'.\random.txt','r+').readlines()
cnt = 0
for i in range(104):
pre.setrandbits(int(data[i*3+0]),32)
pre.setrandbits(int(data[i*3+1]),64)
pre.setrandbits(int(data[i*3+2]),96)
print(cnt)
from hashlib import md5
flag = md5(str(pre.getrandbits(32)).encode()).hexdigest()
print(flag)