NewStarCTF Prng题解

from Crypto.Util.number import *
flag = b'xxxxxxxxxxxxxxxxxxxx'

class my_prng_lcg:
    def __init__(self, seed, multiplier, increment, modulus):
        self.state = seed
        self.multiplier = multiplier
        self.increment = increment
        self.modulus = modulus

    def random(self):
        self.state = (self.state * self.multiplier + self.increment) % self.modulus
        return self.state

PRNG = my_prng_lcg(bytes_to_long(flag), getRandomInteger(256), getRandomInteger(256), getRandomInteger(256))
gift = []
for i in range(6):
    gift.append(PRNG.random())

qwq = bytes_to_long(flag)
print(qwq.bit_length())
print(gift)
# [32579077549265101609729134002322479188058664203229584246639330306875565342934, 30627296760863751873213598737521260410801961411772904859782399797798775242121, 59045755507520598673072877669036271379314362490837080079400207813316110037822, 29714794521560972198312794885289362350476307292503308718904661896314434077717, 3378007627369454232183998646610752441039379051735310926898417029172995488622, 35893579613746468714922176435597562302206699188445795487657524606666534642489]

观察题目,这是一道prng,已知6个随机数,那我们下面便是要预测随机数。

观察代码,这是一道LCG,解题思路便是通过线性关系推出线性方程

s0=32579077549265101609729134002322479188058664203229584246639330306875565342934
s1=30627296760863751873213598737521260410801961411772904859782399797798775242121
s2=59045755507520598673072877669036271379314362490837080079400207813316110037822
s3=29714794521560972198312794885289362350476307292503308718904661896314434077717
s4=3378007627369454232183998646610752441039379051735310926898417029172995488622
s5=35893579613746468714922176435597562302206699188445795487657524606666534642489

写出关系式

s1 = (s0*self.nultipler+self.increment)mod self.modulus
s2 = (s1*self.nultipler+self.increment)mod self.modulus
s3 = (s2*self.nultipler+self.increment)mod self.modulus
s4 = (s3*self.nultipler+self.increment)mod self.modulus
s5 = (s4*self.nultipler+self.increment)mod self.modulus


这道题目我们首要目的是求 self.modulus
因为所有的运算都是建立在模上的
通过x = 0 mod n 展开我们得到x =kn。
由此可以通过构造几个这样的式子求公约数,这样可以得到n。(为了避免偶然性,最好多找几个)
构造第一步,通过相邻式子相减消掉self.increment之后根据目标构造

下面给出我的构造代码

t0=s1-s0
t1=s2-s1
t2=s3-s2
t3=s4-s3
t4=s5-s4
x=t2*t0-t1*t1
y=t3*t1-t2*t2
modulus= math.gcd(x,y)

m求出来以后

便是求另外两个未知数

由于self.increment 可以通过式子相减消去

因此先求出self.nultipler,再求出self.increment

下面给出代码

multiplier = (s2 - s1) *gmpy2.invert(s1 - s0, modulus) % modulus
increment = (s1 - s0*multiplier) % modulus

到这边,我们已经求出了线性方程,下面开始求flag

通过题目可以发现,flag藏在seed里面

即通过s0求出seed,转flag

给出代码

seed = (s0-increment) * gmpy2.invert(multiplier-0, modulus) %modulus
flag = long_to_bytes(seed)

下面给出完整代码

import math
from Crypto.Util.number import *
import gmpy2
s0=32579077549265101609729134002322479188058664203229584246639330306875565342934
s1=30627296760863751873213598737521260410801961411772904859782399797798775242121
s2=59045755507520598673072877669036271379314362490837080079400207813316110037822
s3=29714794521560972198312794885289362350476307292503308718904661896314434077717
s4=3378007627369454232183998646610752441039379051735310926898417029172995488622
s5=35893579613746468714922176435597562302206699188445795487657524606666534642489
t0=s1-s0
t1=s2-s1
t2=s3-s2
t3=s4-s3
t4=s5-s4
x=t2*t0-t1*t1
y=t3*t1-t2*t2
modulus= math.gcd(x,y)
multiplier = (s2 - s1) *gmpy2.invert(s1 - s0, modulus) % modulus
increment = (s1 - s0*multiplier) % modulus
seed = (s0-increment) * gmpy2.invert(multiplier-0, modulus) %modulus
flag = long_to_bytes(seed)
print(flag)
posted @ 2022-10-16 20:06  m0feng  阅读(94)  评论(0编辑  收藏  举报