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)