题就是一下一段代码:
from Crypto.Util.number import *
from flag import flag
state = bytes_to_long(flag.encode())
p = getPrime(128)
q = getPrime(128)
m = p * q
a, b = [getRandomRange(0, m) for _ in range(2)]
with open('output', 'w') as f:
f.write(str(m) + '\n')
for i in range(6):
state = (a*state + b) % m
if i & 1 == 0:
f.write(str(state) + '\n')
#output
#55584485421406970301254549526604327461056610434113867867423369210521481715933
#3693929062344887200388436902170299368192364992317574256526074702481265639773
#23589540966217424118104948577678311766405141841319921607964145788046048746955
#47328186237445429020074319580472604276783097851624136984720842711863174734878
其实上面就是lcg 的一个实现,现在就是需要在给出不连续state 和只已知一个模数的情况下,去获得最原始的seed。
其实可以整理下,现在已有的信息:
m 已知 1-1
s0 = (a*flag+b) % m 已知
s1 = (a*s0+b) % m 未知
s2 = (a*s1+b) % m 已知
s3 = (a*s2+b) % m 未知
s4 = (a*s3+b) % m 已知
s5 = (a*s4+b) % m 未知
运算法则: 2-1
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
(a^b) % p = ((a % p)^b) % p
结合上述,可以做出推导:
整理1-1,可以得出
s2 = (a*s1+b) % m
= (a*((a*s0+b)%m)+b)%m
= ((a^2*s0+a*b)%m+b)%m
= ((a^2*s0+a*b)%m+b%m)%m
= ((a^2)*s0+(a*b+b))%m
同理
s4 = ((a^2)*s2+(a*b+b)) % m
有1-3,1-4可以得出三个已知的方程
s0
s2 = ((a^2)*s0+(a*b+b))%m
s4 = ((a^2)*s2+(a*b+b))%m
上述可以看成已知三个连续的state,并且m已知,这时我们可以求出增量和倍数,也就是A和B
print modulus
# 55584485421406970301254549526604327461056610434113867867423369210521481715933
print multiplier
# 29895665113034070831270870121097218673769521820755738885706707818988524697486
print increment
# 10970971392662008355932635955522286958108129801799159674070281034705667949016
所以接下来的问题就是转成要求解a,b
现已知
a^2 %m = multiplier 3-1
(a*b+b) %m = increment 3-2
3-1 就是转换成了rabin算法求a,可以求出四个值
a1 = 12148216982102969041413774652541055317530796166508320865750841994931663264578
a2 = 20571673399268668407559869739243400173392957535417524496976391648674023475520
a3 = 35012812022138301893694679787360927287663652898696343370446977561847458240413
a4 = 43436268439304001259840774874063272143525814267605547001672527215589818451355
再去带入3-2求b
b1=40178748872227647611096328277557463759078686151834935754250972229282936221637
b2=15546661475754637573198741107073476410343974651382921367731251271526010457262
b3=54246133007752214080959135106794301899992118363091740494393394670479908238584
b4=29614045611279204043061547936310314551257406862639726107873673712722982474209
最后带入s1=(s0*a + b)%m
求s0
s01=6470386600949504443694099817268924704146998350414119656813754417606076026992
s02=46327402297746304187574024387239286474818481647613445016995530037063970024829
s03=23465392185760547466583851826628491835517611366861216845129115904941948671017
s04=7737922461150376909209226869994526145132484229946674337887522313878360952921
其中可显字符为
#flag{Qu1t3_4n_34sy_m4th_pr0blem}
最终脚本
from Crypto.Util.number import *
#from flag import flag
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, x, y = egcd(b % a, a)
return (g, y - (b // a) * x, x)
def modinv(b, n):
g, x, _ = egcd(b, n)
if g == 1:
return x % n
m = 55584485421406970301254549526604327461056610434113867867423369210521481715933
s0 = 3693929062344887200388436902170299368192364992317574256526074702481265639773
s2 = 23589540966217424118104948577678311766405141841319921607964145788046048746955
s4 = 47328186237445429020074319580472604276783097851624136984720842711863174734878
def crack_unknown_increment(states, modulus, multiplier):
increment = (states[1] - states[0]*multiplier) % modulus
return modulus, multiplier, increment
def crack_unknown_multiplier(states, modulus):
multiplier = (states[2] - states[1]) * modinv(states[1] - states[0], modulus) % modulus
return crack_unknown_increment(states, modulus, multiplier)
modulus, multiplier, increment = crack_unknown_multiplier([s0, s2, s4], m)
print modulus
print multiplier
print increment
# 55584485421406970301254549526604327461056610434113867867423369210521481715933
# 29895665113034070831270870121097218673769521820755738885706707818988524697486
# 10970971392662008355932635955522286958108129801799159674070281034705667949016
#https://alpertron.com.ar/QUADMOD.HTM
a1 = 12148216982102969041413774652541055317530796166508320865750841994931663264578
a2 = 20571673399268668407559869739243400173392957535417524496976391648674023475520
a3 = 35012812022138301893694679787360927287663652898696343370446977561847458240413
a4 = 43436268439304001259840774874063272143525814267605547001672527215589818451355
b1=40178748872227647611096328277557463759078686151834935754250972229282936221637
b2=15546661475754637573198741107073476410343974651382921367731251271526010457262
b3=54246133007752214080959135106794301899992118363091740494393394670479908238584
b4=29614045611279204043061547936310314551257406862639726107873673712722982474209
s01=6470386600949504443694099817268924704146998350414119656813754417606076026992
s02=46327402297746304187574024387239286474818481647613445016995530037063970024829
s03=23465392185760547466583851826628491835517611366861216845129115904941948671017
s04=7737922461150376909209226869994526145132484229946674337887522313878360952921
print long_to_bytes(s01)
print long_to_bytes(s02)
print long_to_bytes(s03)
print long_to_bytes(s04)
#flag{Qu1t3_4n_34sy_m4th_pr0blem}
参考资料:
其实让我一开始不能理解的地方在于
这个点,可能是我的基本功不太扎实,一开始直接想成了这个方程,我要去补充学习下基础知识了。
这就导致了结果很奇怪了。
后面的a,b求解,因为找到了一个在线的可以解最多两次的方程同余的网站,就不写代码了。还是能够很快速的求解的。