LCG题,整理一下做法。
题目源码如下:
from Crypto.Util.number import *
from random import *
import hashlib
from pwn import *
p = getPrime(128)
seed = randint(2, p - 1)
c = 114514
e = int(2e8)
class prng:
n = p
a,b = [randint(2, p - 1) for _ in range(2)]
def __init__(self,seed):
self.state = seed
def next(self):
self.state = (self.state * self.a + self.b) % self.n
return self.state
def test():
gen = prng(seed)
print(seed)
print(gen.next())
print(gen.next())
print(gen.next())
print(gen.next())
print(gen.next())
print(gen.next())
def m_func(i):
if i == 0: return 1
return a*c**i+b*m_func(i-1)+n
def encrypt_flag(sol):
sol = sol % (10**10000)
sol = str(sol)
sol_md5 = hashlib.md5(sol.encode()).hexdigest()
return xor(sol_md5.encode(),flag)
if __name__ == "__main__":
test()
sol = m_func(e)
print(encrypt_flag(sol))
'''
150532854791355748039117763516755705063
335246949167877025932432065299887980427
186623163520020374273300614035532913241
215621842477244010690624570814660992556
220694532805562822940506614120520015819
17868778653481346517880312348382129728
160572327041397126918110376968541265339
b'UUV\x04H\x01T\x01P\x03\t\x04\t\x1fW\x00T\x02LRSPT\x1d\x02\x02^\x01N[\\R\x02\tSV\x07\x06P\x01QK'
'''
基本的逻辑是已知LCG随机数种子和前6个随机数,要反推参数a,b和p
然后根据sol的算法解出flag。
LCG反推部分主要参考这篇文章:
CTF中LCG算法总结
lcg-5这种情况,推演一下设
t
n
=
X
n
+
1
−
X
n
=
(
a
X
n
+
b
)
−
(
a
X
n
−
1
+
b
)
m
o
d
p
t_n=X_{n+1}-X_n=(aX_n+b)-(aX_{n-1}+b) \mod p
tn=Xn+1−Xn=(aXn+b)−(aXn−1+b)modp
则
t
n
=
a
t
n
−
1
m
o
d
p
⟹
t
n
+
1
t
n
−
1
−
t
n
t
n
=
(
a
a
t
n
−
1
t
n
−
1
−
a
t
n
−
1
a
t
n
−
1
)
=
0
m
o
d
p
t_n=at_{n-1} \mod p \Longrightarrow t_{n+1}t_{n-1}-t_nt_n=(aat_{n-1}t_{n-1}-at_{n-1}at_{n-1})=0 \mod p
tn=atn−1modp⟹tn+1tn−1−tntn=(aatn−1tn−1−atn−1atn−1)=0modp
即
T
n
=
t
n
+
1
t
n
−
1
−
t
n
t
n
T_n=t_{n+1}t_{n-1}-t_nt_n
Tn=tn+1tn−1−tntn是
p
p
p的倍数,
p
=
g
c
d
(
T
n
,
T
n
−
1
)
p=gcd(T_n,T_{n-1})
p=gcd(Tn,Tn−1)
再根据
X
n
+
2
−
X
n
+
1
=
a
X
n
+
1
+
b
−
a
X
n
−
b
m
o
d
p
=
a
(
X
n
+
1
−
X
n
)
m
o
d
p
X_{n+2}-X_{n+1}=aX_{n+1}+b-aX_{n}-b \mod p=a(X_{n+1}-X_n) \mod p
Xn+2−Xn+1=aXn+1+b−aXn−bmodp=a(Xn+1−Xn)modp
得到
a
=
(
X
n
+
2
−
X
n
+
1
)
(
X
n
+
1
−
X
n
)
−
1
m
o
d
p
a=(X_{n+2}-X_{n+1})(X_{n+1}-X_n)^{-1} \mod p
a=(Xn+2−Xn+1)(Xn+1−Xn)−1modp
最后计算
b
=
X
n
+
1
−
a
X
n
m
o
d
p
b=X_{n+1}-aX_{n} \mod p
b=Xn+1−aXnmodp
套脚本:
from math import gcd
from gmpy2 import invert
x = [150532854791355748039117763516755705063,
335246949167877025932432065299887980427,
186623163520020374273300614035532913241,
215621842477244010690624570814660992556,
220694532805562822940506614120520015819,
17868778653481346517880312348382129728,
160572327041397126918110376968541265339]
t = [x[i+1] - x[i] for i in range(len(x)-1)]
def f(i):
return t[i]*t[i+2]-t[i+1]*t[i+1]
p = gcd(f(0), f(1))
print('p=',p)
a = invert(x[1]-x[0], p)
a = a * (x[2]-x[1]) % p
print('a=',a)
b = (x[1] - x[0] * a) % p
print('b=',b)
求出a,b,p后问题就变为解决my_func()函数递归时间复杂度的问题。
主要用到矩阵快速幂算法,参考
矩阵快速幂详解
写成
f
(
i
)
=
a
c
i
+
b
f
(
i
−
1
)
+
p
f(i)=ac^i+bf(i-1)+p
f(i)=aci+bf(i−1)+p
进一步构造转移矩阵:
[
f
(
i
)
c
i
p
]
=
[
b
a
c
1
0
c
0
0
0
1
]
∗
[
f
(
i
−
1
)
c
i
−
1
p
]
\left[\begin{array}{ccc} f(i)\\ c^i\\ p\\ \end{array}\right] =\left[\begin{array}{ccc} b & ac & 1 \\ 0 & c & 0 \\ 0 & 0 & 1 \\ \end{array}\right] *\left[\begin{array}{ccc} f(i-1) \\ c^{i-1} \\ p \\ \end{array}\right]
⎣
⎡f(i)cip⎦
⎤=⎣
⎡b00acc0101⎦
⎤∗⎣
⎡f(i−1)ci−1p⎦
⎤
右侧展开:
[
f
(
i
)
c
i
p
]
=
[
b
a
c
1
0
c
0
0
0
1
]
i
∗
[
f
(
0
)
c
0
p
]
\left[\begin{array}{ccc} f(i)\\ c^i\\ p\\ \end{array}\right] =\left[\begin{array}{ccc} b & ac & 1 \\ 0 & c & 0 \\ 0 & 0 & 1 \\ \end{array}\right]^{i} *\left[\begin{array}{ccc} f(0) \\ c^{0} \\ p \\ \end{array}\right]
⎣
⎡f(i)cip⎦
⎤=⎣
⎡b00acc0101⎦
⎤i∗⎣
⎡f(0)c0p⎦
⎤
上exp:
from hashlib import md5
from Crypto.Util.strxor import *
p= 339088189917874808463944743121467561531
a= 259086495324961642923203668736965982268
b= 121870392737324465817476070178603827899
c = 114514
e = int(2e8)
mod=10 ** 10000
M=matrix(Zmod(mod),[[b,a*c,1],[0,c,0],[0,0,1]])
C=matrix(Zmod(mod),[[1,1,p]])
C=C.T #matrix transpose
s=(M^e)*C
sol = str(s[0])[1:10001] #注意去掉前后括号
enc=b'UUV\x04H\x01T\x01P\x03\t\x04\t\x1fW\x00T\x02LRSPT\x1d\x02\x02^\x01N[\\R\x02\tSV\x07\x06P\x01QK'
sol_md5 = md5(sol.encode()).hexdigest()
print(strxor((2*sol_md5.encode())[:42],enc))