[GKCTF 2021]Random

题目
在这里插入图片描述

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)

解题

通过读代码,知道是求生成104组随机数之后的一个随机数

通过算法出的随机数是伪随机数,这里用到的随机数生成函数是random.getrandbits(k)

random.getrandbits(k)
返回具有 k 个随机比特位的非负 Python 整数。 此方法随 MersenneTwister 生成器一起提供,其他一些生成器也可能将其作为 API 的可选部分提供。 在可能的情况下,getrandbits() 会启用 randrange() 来处理任意大的区间。
在 3.9 版更改: 此方法现在接受零作为 k 的值。

所以这又是梅森算法了, MersenneTwister是为了解决过去伪随机数生成器PRNG产生的伪随机数质量不高而生成的。(指路详细解析梅森旋转算法:传送门)。我们了解到 MT19937能做生成在 1≤k≤623 个32位均匀分布的随机数。而正巧我们已经有624( 104 + 104 ∗ ( 64 / 32 ) + 104 ∗ ( 96 / 32 ) = 624 104+104*(64/32)+104*(96/32)=624 104+104(64/32)+104(96/32)=624)个生成的随机数了,也就是说,根据已经有的随机数我们完全可以推出下面会生成的随机数。

需要用到的是randcrack的库

先了解一下randcrack

randcrack
工作原理
该生成器基于 M e r s e n n e T w i s t e r MersenneTwister MersenneTwister(梅森算法),能够生成具有优异统计特性的数字(与真正的随机数无法区分)。但是,此生成器的设计目的不是加密安全的。您不应在关键应用程序中用作加密方案的PRNG。
您可以[在维基百科上]了解有关此生成器的更多信息(https://en.wikipedia.org/wiki/Mersenne_Twister).
这个饼干的工作原理如下。
它从生成器获得前624个32位数字,并获得Mersenne Twister矩阵的最可能状态,即内部状态。从这一点来看,发电机应该与裂解器同步。
如何使用
将生成器生成的32位整数准确地输入cracker非常重要,因为它们无论如何都会生成,但如果您不请求它们,则会删除它们。 同样,您必须在出现新种子之后,或者在生成 624 ∗ 32 624*32 62432位之后,准确地为破解程序馈电,因为每个 624 ∗ 32 624*32 62432位数字生成器都会改变其状态,并且破解程序设计为从某个状态开始馈电。

(忘了这一段是从哪里复制下来仍百度翻译的结果了)
大致意思就是:
RandCrack中有一个方法是predict_getrandbits(),在给出的随机数数量多时,可以预测下一个随机数。

脚本参考

from hashlib import md5
from randcrack import RandCrack
def foo(l,i):
    a=[]
    a.append(l[i])
    b1=l[i+1]>>32
    b2=l[i+1]&(2**32-1)
    a.append(b2)
    a.append(b1)
    b1=l[i+2]>>64
    b2=(l[i+2]&(2**64-1))>>32
    b3=l[i+2]&(2**32-1)
    a.append(b3)
    a.append(b2)
    a.append(b1)
    return a
with open(r'random.txt','r') as f:
    l=f.readlines()
l=[int(i.strip()) for i in l]
ll=[]
for i in range(0,len(l),3):
    ll+=foo(l,i)
rc=RandCrack()
for i in ll:
    rc.submit(i)
aa=rc.predict_getrandbits(32)
print(md5(str(aa).encode()).hexdigest())

代码就很容易读懂了,先将我们有的随机数排列到一个列表ll中,然后挨个用RandCrack.submit()提交,最后用RandCrack.predict_getrandbits()预测下一个32位随机数,然后md5一下输出就好了

运行得到:14c71fec812b754b2061a35a4f6d8421

答案

GKCTF{14c71fec812b754b2061a35a4f6d8421}
(坑人,检查好几遍不知道哪错了,最后发现错到格式上了)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐