Skip to content

Instantly share code, notes, and snippets.

@Edward-L
Created January 17, 2020 08:19
Show Gist options
  • Save Edward-L/232360fed56cf3b7a36cb8f37a2bbea0 to your computer and use it in GitHub Desktop.
Save Edward-L/232360fed56cf3b7a36cb8f37a2bbea0 to your computer and use it in GitHub Desktop.

题就是一下一段代码:

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}

参考资料:

https://alpertron.com.ar/QUADMOD.HTM

https://xz.aliyun.com/t/5113

https://tailcall.net/blog/cracking-randomness-lcgs/

@Edward-L
Copy link
Author

其实让我一开始不能理解的地方在于

a^2 %m = multiplier  3-1
(a*b+b) %m = increment 3-2

这个点,可能是我的基本功不太扎实,一开始直接想成了这个方程,我要去补充学习下基础知识了。

a^2 = multiplier  3-1
(a*b+b) = increment 3-2

这就导致了结果很奇怪了。
后面的a,b求解,因为找到了一个在线的可以解最多两次的方程同余的网站,就不写代码了。还是能够很快速的求解的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment