0%

2024-N1CTF-wp-crypto

质量很高的题目,记录一下做法,确实不太会对称所以暂时没有做twist这道。赛中完全没有注意到MT所以没有搞定M4sTeriX,有点可惜,还是差了一招。

n0tr5a

题目描述:

1
It's not RSA!

题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from Crypto.Util.number import *
from secret import flag

def gen(nbit, m):
kbit = int(nbit * 0.4512)
key = getPrime(kbit)

while True:
p = getPrime(nbit // 2 - 1)
if isPrime(p * 2 + 1):
p = p * 2 + 1
break
while True:
q = getPrime(nbit // 2 - 1)
if isPrime(q * 2 + 1):
q = q * 2 + 1
break
n = p * q
phi = (p - 1) * (q - 1)

e, k = [], []
for i in range(m):
dd = key + 2 * i + 2
ee = inverse(dd, phi)
kk = (ee * dd - 1) // phi
e.append(ee % 2 ** (nbit - kbit))
k.append(kk)

return n, e, k

n, e, k = gen(1024, 12)
enc = pow(bytes_to_long(flag), 65537, n)

with open("data.txt","w") as f:
f.write(f"{n = }\n{enc = }\n{e = }\n{k = }\n")

data.txt:

1
2
3
4
n = 82699881935193109791472212259236125591789180928354081401868164018417228277481034922264132029171387301840769422435233519725339633533151517379984801310897094212731380971539763520078187279519479595450340858225632773423726273875857681742976022998251134553236897670416440247498103588885527592983304472279634643957
enc = 36794479248642872612364238056628323098776595394584051168003253681308381469543148020365981382945118247106425767548419728448043683874348775891060829403456974633618540620271474325940287199561651410530249693150249056719801828452373946254944967790634308791835260415588851915975925342336816758487259438650490430459
e = [8888429835496095643535631191491505388277997809079089914782728064936463291203724475916011147975968533541243766266627762336328575049254500085648004975612619037464278832991, 10520875896679093312405671804517920324087646023792222747154447628464758710245963882871820387158134686949159913616463457692301596583039366392879522319633770989600617793993, 10601203527211713579180750988795815135916059018550710650265113080975290409723984434909955571406050178911560767494058644740527759576770265488136304573804742084915697171019, 14622236712746402638071905642098139610445903171562565245220543995502178907758821801160631615531163735803555926497329822620058537286662778517871290983128596096302228266209, 13754445300340270191221556210805776985685382903218031894668871565239317628261744219992643635369635181508144912605084390638097003753479943161757716583483371428111258641999, 12460010632813615553769774340135585477760327095310449594534663078794374775415503111884611193451554799744919010772785354797945533347796386998533715641130155450020923742093, 13453716597070478297648899092689370236302303280643930607214496697603184305419894290940911668951264509281914356651376372996746606791176528956862446530034762390956440975743, 9094611196190891372488960864378207737592838879869747718773801183985658899847575852673983345117604950170885723017205969782710348697632364573814601979741607809886580452089, 6208536025163051261514520489326917558898635960331271412905419257732637120279699170648486672913828237574848376496958272367037120192950777084064981617441543021966571267615, 12222783896133215551045666761401890068457062194802465729916062142356007806837055121210344156062210736292529151537109874603945090163748106129066462428445187619153477674477, 12614188721315363674299785508736495244859114088280924894674179341352352570584522323159835229814636248801721832488735354744616443270824945572498647598651837749451947061719, 1152998684313785798360794952776294245536465631931933802028441841686020994002404128005468864877622660410537371162754781745360983347732927142593427077571775783417497297097]
k = [1420437810145904840211095643676412643944076218177458138046274525430773202929328250820697290122977318065170030510975153884301846687954934017, 3940861961324077864997765290105972644424759701256821322813075596188909751606433001282290039081974406373664979502491212469917425748074824949, 9413004926123376989637174399517514326721338378609741980303584526041973145706068370477394363722601798762946415087687748257511626645382494821, 7428184730507734867291435325705251542125906508735340171046981085055137680467341685699246562820294813340827360115146667698628846494205603434, 5807754291508765665701362465833864063188458758878871682965086597196662689504909848658274758620320439529911831751168255058459646445501084679, 4757450447044159731910445277826227301213629775871240625040932054281107227037248484860063739616068171487636025286033326826668030840136004650, 5996697334509086666652114545471399499880715834871318018958944856630439665570432872031097645146070471243016581178433327374429447296670643144, 34948977643936917247938455046939890895031986466384330025838204273490152867215005144463212975331851051065343323158463423475270019458998722, 2108517589993394132588916598627794212409854321151001283809351367884838987309441276260578523735992656738890197115589763805165681991611220869, 7529989400759036686155222444072464272422956186987614547747593414852898515920566835606491795646900457120392171067632339816915038614860409008, 5919516150531691402185931957988063032510639008912552676259537229103356758278878266990953285696298526725065525943655778090084815308411600528, 6143553530848821997030657441615076975797083210691917101599644261591827822351051233391184584862183963084085114519636359680935327311007033284]

题目先生成一个462bit的素数当作key,之后生成两个512bit的安全素数p、q,然后给出12轮hint,每一轮中:

给出每一轮的ee的低562位以及kk,要求分解n来解最后的RSA密文。

把hint代进等式就有:

可以看出在模$2^{562}$下满足:

记:

那么有:

这是个线性等式,且$p+q$和$key$在模$2^{562}$下都不大,所以可以LLL得到,之后解方程就可以分解n。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from Crypto.Util.number import *
from gmpy2 import *

kbit = int(1024 * 0.4512)
n = 82699881935193109791472212259236125591789180928354081401868164018417228277481034922264132029171387301840769422435233519725339633533151517379984801310897094212731380971539763520078187279519479595450340858225632773423726273875857681742976022998251134553236897670416440247498103588885527592983304472279634643957
enc = 36794479248642872612364238056628323098776595394584051168003253681308381469543148020365981382945118247106425767548419728448043683874348775891060829403456974633618540620271474325940287199561651410530249693150249056719801828452373946254944967790634308791835260415588851915975925342336816758487259438650490430459
e = [8888429835496095643535631191491505388277997809079089914782728064936463291203724475916011147975968533541243766266627762336328575049254500085648004975612619037464278832991, 10520875896679093312405671804517920324087646023792222747154447628464758710245963882871820387158134686949159913616463457692301596583039366392879522319633770989600617793993, 10601203527211713579180750988795815135916059018550710650265113080975290409723984434909955571406050178911560767494058644740527759576770265488136304573804742084915697171019, 14622236712746402638071905642098139610445903171562565245220543995502178907758821801160631615531163735803555926497329822620058537286662778517871290983128596096302228266209, 13754445300340270191221556210805776985685382903218031894668871565239317628261744219992643635369635181508144912605084390638097003753479943161757716583483371428111258641999, 12460010632813615553769774340135585477760327095310449594534663078794374775415503111884611193451554799744919010772785354797945533347796386998533715641130155450020923742093, 13453716597070478297648899092689370236302303280643930607214496697603184305419894290940911668951264509281914356651376372996746606791176528956862446530034762390956440975743, 9094611196190891372488960864378207737592838879869747718773801183985658899847575852673983345117604950170885723017205969782710348697632364573814601979741607809886580452089, 6208536025163051261514520489326917558898635960331271412905419257732637120279699170648486672913828237574848376496958272367037120192950777084064981617441543021966571267615, 12222783896133215551045666761401890068457062194802465729916062142356007806837055121210344156062210736292529151537109874603945090163748106129066462428445187619153477674477, 12614188721315363674299785508736495244859114088280924894674179341352352570584522323159835229814636248801721832488735354744616443270824945572498647598651837749451947061719, 1152998684313785798360794952776294245536465631931933802028441841686020994002404128005468864877622660410537371162754781745360983347732927142593427077571775783417497297097]
k = [1420437810145904840211095643676412643944076218177458138046274525430773202929328250820697290122977318065170030510975153884301846687954934017, 3940861961324077864997765290105972644424759701256821322813075596188909751606433001282290039081974406373664979502491212469917425748074824949, 9413004926123376989637174399517514326721338378609741980303584526041973145706068370477394363722601798762946415087687748257511626645382494821, 7428184730507734867291435325705251542125906508735340171046981085055137680467341685699246562820294813340827360115146667698628846494205603434, 5807754291508765665701362465833864063188458758878871682965086597196662689504909848658274758620320439529911831751168255058459646445501084679, 4757450447044159731910445277826227301213629775871240625040932054281107227037248484860063739616068171487636025286033326826668030840136004650, 5996697334509086666652114545471399499880715834871318018958944856630439665570432872031097645146070471243016581178433327374429447296670643144, 34948977643936917247938455046939890895031986466384330025838204273490152867215005144463212975331851051065343323158463423475270019458998722, 2108517589993394132588916598627794212409854321151001283809351367884838987309441276260578523735992656738890197115589763805165681991611220869, 7529989400759036686155222444072464272422956186987614547747593414852898515920566835606491795646900457120392171067632339816915038614860409008, 5919516150531691402185931957988063032510639008912552676259537229103356758278878266990953285696298526725065525943655778090084815308411600528, 6143553530848821997030657441615076975797083210691917101599644261591827822351051233391184584862183963084085114519636359680935327311007033284]

L = Matrix(ZZ, 3+len(e), 3+len(e))
for i in range(3):
L[i,i] = 1
for i in range(len(e)):
Ci = e[i]*(2*i+2) - 1 - k[i]*(n+1)
L[0, 3+i] = e[i]
L[1, 3+i] = k[i]
L[2, 3+i] = Ci
for i in range(len(e)):
L[-i-1,-i-1] = 2^(1024 - kbit)
L[0,0] = 2^(513-kbit)
L[2,2] = 2^513
L[:,3:] *= n

res = L.LLL()[0]
key = abs(res[0])
pplusq = abs(res[1])

pminusq = iroot(pplusq^2-4*n,2)[0]
p = (pplusq + pminusq) // 2
q = n // p
d = inverse(65537,(p-1)*(q-1))
assert p*q == n
print(long_to_bytes(int(pow(enc,d,n))))


#n1ctf{7hE_Br1l1!4nCe_0f_D5tErm1Nan7_4Nd_C0PP5R4m|Th!}



seashells

题目描述:

1
Searching for  Seashells🐚 by the seaside🏝️ : )

题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
FLAG = "n1ctf{REDACTED}"
ells = [*primes(3, 250), 661]
p = 4 * prod(ells) - 1
F = GF(p**2, 'i')

class Seaside:
def __init__(self):
self.pearls = getrandbits(len(ells))

def wave(self, A, Q=0, signal=False):
E = EllipticCurve(F, [0, A, 0, 1, 0]); Q = E(Q)
if not signal: priv = [randint(0, 3) for _ in range(len(ells))]
else: priv = [int(i) for i in bin(self.pearls)[2:].zfill(len(ells))]
for e, ell in zip(priv, ells):
for _ in range(e):
E.set_order((p+1)**2)
P = self.pebble(E, ell); P.set_order(ell)
phi = E.isogeny(P)
E, Q = phi.codomain(), phi(Q)
Em = E.montgomery_model(); phi = E.isomorphism_to(Em)
return (Em.a2(), phi(Q))

def pebble(self, E, ell):
set_random_seed(1337)
while not (P := (p + 1) // ell * E.random_element()): pass
set_random_seed(randint(0,p))
return P

def tide(self):
shore = self.wave(0)[0]
print("Shore", shore)
return self.wave(shore, input("Seashells > ").split(','), True)[1].xy()

def chall(self):
if int(input("Pearls > ")) == self.pearls:
print(FLAG)

alarm(1200)
sys = Seaside()
for _ in range(30):
print(sys.tide())

sys.chall()

题目基于CSIDH,连接上靶机后,靶机会生成一个随机数pearls,我们的目的就是求出pearls来。

为了达到这个目的,题目给了我们30轮交互机会(必须要用完),每次交互过程为:

  • 靶机随机生成私钥列表,该私钥列表由0-3的元素组成,用这个私钥进行同源得到一条曲线并给出,记为E1
  • 我们拿到E1后,可以选择E1上的一个点$Q$发送给靶机
  • 靶机之后会将parls的比特串当作私钥列表进行同源,并将我们选择的点经过同源映射后的$\phi(Q)$返回给我们

与一般的CSIDH过程相比,题目不同的点在于工作域放在了二次扩域而不是一次域,这直接影响了CSIDH的工作机理,因为在一次域上,对于一个小素因子来说,其邻居是确定的,而二次扩域上则会有不同的邻居(参考SIDH)。

此外还有一个奇怪的地方就是每次同源靶机选择torsion points的方式,也就是下面的这个pebble函数:

1
2
3
4
5
def pebble(self, E, ell):
set_random_seed(1337)
while not (P := (p + 1) // ell * E.random_element()): pass
set_random_seed(randint(0,p))
return P

可以看出,对于一条确定的曲线来说,由于种子固定,选择的torsion points也就是固定的。

方法一

接下来进入解题,首先,由于我们可以自己构造点$Q$并获得同源后的$\phi(Q)$,这就很类似于imaginaryCTF的coast一题。在coast中,由于同源工作在一次域上,每个素因子q只有q-torsion里独特的一个分支,所以我们发送的点在经历q-isogeny之后,这个点阶的因子q一定会消失,所以可以通过判断返回的点的阶来得到私钥列表。

而这个题不一样,由于torsion在二次域上有多个分支,所以当且仅当我们发送的Q与本次同源的kernel在同一个群中的时候,Q的阶在经历q-isogeny之后,其阶的因子q才会消失。

而由于我们有E1,并且pebble函数生成kernel的时候会固定种子为1337,所以一个很自然的思路就产生了:

  • 从素因子3开始,我们假设其对应的私钥是1,那么由于我们有E1,因此我们同样可以设置种子为1337,并通过pebble求出本次同源的kernel

  • 我们就选这个kernel当作$Q$发送给靶机,那么当靶机返回$\phi(Q)=O$的时候,就说明3对应的私钥的确是1,否则就是0

  • 此时我们就知道了私钥列表中3这个素因子对应的值,这代表着我们能够知道下一次我们拿到的E1经过这个值后到达的曲线,记为$E1_{3}$

  • 那么继续这个过程,我们假设素因子5对应的私钥是1,我们同样可以通过pebble获得这个5-isogeny的kernel,记这个kernel为$Q_5$。而现在我们只要让发送的$Q$满足:

    • $\phi_3(Q) = Q_5$

      其实并不需要相等,其实只需要在同一个torsion分支中即可,这样在$\phi_5$之后就会降阶

    为此我们取$\phi_3$的对偶同源$\hat{\phi_3}$,并在$E1_{3}$上随机取一个p+1阶的点$P$,然后取$Q = \hat{\phi_3}(P)$,那么当5对应的私钥的确为1时,我们最后就会收到因为$\phi_5$降过阶的$\phi(Q)$,否则就说明5对应的私钥为0。此时我们就又得到了$E1_{3,5}$

  • 以此类推

这个过程可以反复进行下去,一直到30轮结束的时候,我们总共可以获得前三十个素因子对应的私钥。这引出了一个严峻的问题,素因子列表总共长53,还有23个素因子获得不了,而这23bit靠爆的话,似乎复杂度还是挺高了。

所以这个方法可能可以优化一下,但是我确实没有想到啥优化的好思路。

一个想法是发送的点不直接用kernel,而是取用在乘$\frac{p+1}{q}$之后等于kernel的p+1阶点,这样在最后检查阶的变化时可能会获得其他torsion的自然泄露

此时也许可以加上一些爆破来获得完整的私钥列表

方法二

而突破点依然在于pebble,再仔细看看这个函数:

1
2
3
4
5
def pebble(self, E, ell):
set_random_seed(1337)
while not (P := (p + 1) // ell * E.random_element()): pass
set_random_seed(randint(0,p))
return P

要注意到,最后返回P之前有一个set_random_seed(randint(0,p))的过程,这似乎是为了解除set_random_seed(1337)而设计的,但是由于randint(0,p)也和种子有关,所以这实际上压根没有解除。这代表着在除了第一次pebble之前的随机私钥以外,剩下的一切都是在一个确定的状态下走的!

这甚至会影响wave中的这一行:

1
if not signal: priv = [randint(0, 3) for _ in range(len(ells))]

这代表着一旦某两次进入pebble的曲线一样,那么这两次同源将会完全一样,并且这两次同源之后的包括生成0-3的priv列表在内的所有步骤都会完全一样,这就会产生一个循环节。

实际测试一下会发现这种循环节太容易产生了,因此我们很轻松的就可以在30轮交互中收到两次一模一样的曲线E1,之后我们就取E1上的两个阶为p+1且在两个不同分支中的点$Q_1,Q_2$,那么比如对于3-isogeny来说,我们计算:

那么如下点会生成3-torsion的所有分支:

为什么会有这个结果,用配对的角度去想会比较简单,记:

那么显然有:

由weil pairing的性质可以知道几个事实:

  • weil pairing的函数值是个3次单位根,因此$e(Q_{1,3}, Q_{2,3})$是个生成元,所以对于不同的i结果不同
  • weil pairing本质是对torsion不同分支的配对,因此不同函数值对应torsion的不同分支

所以如果3对应的私钥是1的话,由于$\phi(Q_{1,3}) + i\phi(Q_{2,3})$一定会遍历到所有的3-$torsion$,所以如果经历了3-isogeny,一定有一个分支是对应的kernel,那么就存在一个结果的因子3会消失;这也就是说遍历0-2的值,这个结果一定会有一个是单位元。否则说明3对应的私钥是0。

这种方法就很简单,我们只需要找到两次一模一样的曲线,然后发送两个对任何q-torsion都不在同一个分支的Q1、Q2即可,然后就可以一次性计算出全部的私钥列表了。

而实际脚本编写的角度倒完全不用这样,因为对于后面素因子来说实际上很难在同一个torsion里,主要是前面的3、5、7这种小素因子比较容易出偏差,所以不用全部检查一遍。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from Crypto.Util.number import *
from tqdm import *
from pwn import *

ells = [*primes(3, 250), 661]
p = 4 * prod(ells) - 1
F = GF(p**2, 'i')

sh = process(["sage", "seashells.sage"])
#sh = remote("120.26.69.200", 50979)

def check(G1,G2):
for q in ells[:4]:
qG1 = ((p+1)//q) * G1
qG2 = ((p+1)//q) * G2
if(qG1.weil_pairing(qG2, q) == 1):
return False
return True

Gs = []
Qs = []
As = []
Es = 0
for i in trange(30):
sh.recvuntil(b"Shore ")
A = sh.recvline().strip().decode()
E = EllipticCurve(F, [0, A, 0, 1, 0])
E.set_order((p+1)^2)

if(A in As):
G1 = Gs[As.index(A)]
while(1):
G = E.random_element()
if(G.order() == (p+1) and check(G,G1)):
break
else:
while(1):
G = E.random_element()
if(G.order() == (p+1)):
break

Seashells = str(G.xy())[1:-1]
sh.sendline(Seashells.encode())

sh.recvuntil(b"Seashells > ")
Q = sh.recvline().strip().decode()[1:-1].split(",")
x1, y1 = F(Q[0]), F(Q[1])

PR.<AA> = PolynomialRing(F)
f = y1^2 - (x1^3 + AA*x1^2 + x1)
A1 = f.roots(multiplicities=False)[0]

E1 = EllipticCurve(F, [0, A1, 0, 1, 0])
E1.set_order((p+1)^2)
Q = E1((x1,y1))

if(A in As):
Qs = [Qs[As.index(A)], Q]
Es = E1
times = i + 1
break

Gs.append(G)
Qs.append(Q)
As.append(A)

for i in trange(30 - times):
sh.recvuntil(b"Shore ")
A = sh.recvline().strip().decode()
E = EllipticCurve(F, [0, A, 0, 1, 0])
Q = E.random_element()
sh.recvuntil(b"Seashells > ")
Seashells = str(Q.xy())[1:-1]
sh.sendline(Seashells.encode())

################################################################################################### check
priv = []
for i in tqdm(ells):
Found = 0
for j in range(i):
temp = Qs[0] + j*Qs[1]
if(temp*((p+1)//i) == Es(0)):
Found = 1
priv.append(1)
break
if(Found == 0):
priv.append(0)
print(priv)

pearls = int("".join(list(map(str,priv))), 2)
sh.recvuntil(b"Pearls > ")
sh.sendline(str(pearls).encode())
print(sh.recvline())


#n1ctf{t0r5ion_po1nt_l3aked_my_tre@sure_G_G}

方法三

赛后和hashhash和yolbby一起讨论了好一会儿这个题目,发现在方法一的基础上完全可以加一点优化,使得能够达到如下目的:

  • 每一次交互都可以找到当前已获得私钥列表的后续的第一个0

这是什么意思呢,比如说题目的pearls是:

1
[1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1]

那么用这个优化的方法,每一次交互可以获得:

1
2
3
4
5
[1, 1, 0]
[1, 1, 0, 0]
[1, 1, 0, 0, 1, 0]
[1, 1, 0, 0, 1, 0, 1, 1, 1, 0]
...

思路其实非常简单,假设私钥列表接下来的连续10个值全是1,那么我们能通过pebble获得完整的iso链,也就获得了一个完整的$\phi$,此时我们可以计算他的对偶同源$\hat{\phi}$,而互为dual的同源具有如下性质:

其中d是$\phi$和$\hat{\phi}$的degree。

这里连续多少个值其实不重要,10个值是计算时间和概率做了平衡的结果:

  • 连续10个计算时间不算长
  • 很难有连续10个1出现

那么我们在$phi$后到达的曲线上随机取一个$p+1$阶的点$P$,并计算$\hat{\phi}(P)$作为我们发送给靶机的点$G$,那么如果接下来连续十个值真的都是1,靶机发送给我们的结果就是:

那么$P$的阶就会降低d这么多。

而如果实际上并不是连续十个1,比如在连续两个1之后就断掉了,那么我们发送的$G$在降低前两个素因子的阶之后,阶将不会再下降,而这停止下降的素因子的位置就为我们指示了下一个0的位置。

而这样一来,30次交互,只要当前私钥是1,那么就至少会往前推进两个,所以运气正常的话恢复完整私钥列表就绰绰有余了。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from Crypto.Util.number import *
from tqdm import *
from pwn import *
import random

ells = [*primes(3, 250), 661]
p = 4 * prod(ells) - 1
F = GF(p**2, 'i')

sh = process(["sage", "seashells.sage"])
#sh = remote("120.26.69.200", 50979)
#print(sh.recvline().strip().decode())

def my_pebble(E_start, ell_start, priv, search_length):
phi_back = 1

EE = E_start
for i, ell in zip(priv, ells):
if(i == 1):
set_random_seed(1337)
while not (P := (p + 1) // ell * EE.random_element()): pass
EE.set_order((p+1)**2)
P.set_order(ell)
phi = EE.isogeny(P)
phi_dual = phi.dual()
EE = phi.codomain()
phi_back = phi_back * phi_dual


MAX = min(ell_start+search_length, len(ells)-1)
for ell in ells[ell_start:MAX]:
set_random_seed(1337)
while not (P := (p + 1) // ell * EE.random_element()): pass
EE.set_order((p+1)**2)
P.set_order(ell)
phi = EE.isogeny(P)
phi_dual = phi.dual()
EE = phi.codomain()
phi_back = phi_back * phi_dual

set_random_seed(1337)
while(1):
t = EE.random_element()
if(t.order() == p+1):
break
return phi_back(t)


priv = []
ell_start = 0
for i in range(30):
sh.recvuntil(b"Shore ")
A = sh.recvline().strip().decode()
E = EllipticCurve(F, [0, A, 0, 1, 0])
E.set_order((p+1)^2)

############################################################# pebble find G
G = my_pebble(E, ell_start, priv, 10)
############################################################# pebble find G

Seashells = str(G.xy())[1:-1]
sh.sendline(Seashells.encode())

sh.recvuntil(b"Seashells > ")
Q = sh.recvline().strip().decode()[1:-1].split(",")
x1, y1 = F(Q[0]), F(Q[1])

PR.<AA> = PolynomialRing(F)
f = y1^2 - (x1^3 + AA*x1^2 + x1)
A1 = f.roots(multiplicities=False)[0]

E1 = EllipticCurve(F, [0, A1, 0, 1, 0])
E1.set_order((p+1)^2)
Q = E1((x1,y1))


############################################################# update priv
update_len = 0
for ell in ells[ell_start:ell_start+6]:
if((p+1) // ell * Q == E1(0)):
priv.append(1)
update_len += 1
else:
priv.append(0)
update_len += 1
break
print(priv)
ell_start += update_len
if(len(priv) == len(ells)):
times = i+1
break
############################################################# update priv

for i in trange(30 - times):
sh.recvuntil(b"Shore ")
A = sh.recvline().strip().decode()
E = EllipticCurve(F, [0, A, 0, 1, 0])
Q = E.random_element()
sh.recvuntil(b"Seashells > ")
Seashells = str(Q.xy())[1:-1]
sh.sendline(Seashells.encode())

pearls = int("".join(list(map(str,priv))), 2)
sh.recvuntil(b"Pearls > ")
sh.sendline(str(pearls).encode())
print(sh.recvline())



*M4sTeriX

题目描述:

1
I know that the matrix master is always performing tedious and error-prone matrix operations day after day : (

题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from hashlib import md5
from random import *

FLAG = b"n1ctf{REDACTED}"
N, n, q = 1024, 60, 2**521-1
F, Fq = Zmod(256), GF(q)
s = [random_vector(F, N//2) for _ in range(20)]

def error_work(s, w):
a = random_matrix(F, N//2, N); mat.append(a)
e = list(random_vector(w, x=1, y=256))+[0]*(N-w)
P = Permutations(N).random_element().to_matrix()
return matrix(Fq, 4, N//4, s*a+P*vector(e))

def tedious_work(A):
α = random_matrix(Fq, n, N//4)
ε = matrix(n, N//4, [i*randrange(0, q) for i in α])
σ = matrix(Fq, [[randrange(1, q) for i in range(80)] for j in range(n)])
open("tedious", "w").write(str({"π": list(σ*A+ε), "α": list(α)}))

mat = []
A = matrix(Fq, 80, N//4)
for i in range(20):
A[4*i:4*i+4,:] = error_work(s[i], 22)

save(mat, "mat")
tedious_work(A)
cipher = AES.new(md5(str(sum(s)).encode()).digest(), AES.MODE_ECB)
print(cipher.encrypt(pad(FLAG, 16)).hex())
"""
af3010a3de0fa968c38f421f2857d6c60caf9a6ae1023e9d04f253e1d5fb8038fddf26f7cc976fadbb2df12ef549d1fd
"""

题目先生成了一个长20的列表s,其中每个元素是$Z_{256}$下的512维向量,这是我们需要求解出的会作为AES密钥的内容。

而对于s的内容,题目给了这样一些信息:

  • error_work部分,题目对于s中的每一个向量$\textbf{s}_i$,计算:

    其中$a_i$是$512\times1024$的矩阵,$P_i$是一个随机置换,$e_i$是误差数量为22的error。在这之后把长1024的向量$t_i$拆成一个$4\times 256$的矩阵放入矩阵$A$中,最终会得到一个$80 \times 256$的矩阵$A$

  • tedious_work部分,题目在$F_q$计算了一个:

    并给出$π,α$

接下来就分三个部分来进入解题。

方法一

tedious_work

对于这个部分,我们有$π,α$,以及如下关系式:

注意到在$F_q$下,全为256以内值的$A$显然算小量,因此这其实是个正交格的问题,具体来说,我们用格找到满足如下条件的小值矩阵$M$:

那么代入上式有:

所以对$M$的左核进行规约就可以找到LLL-reduce过的$A$了,记为$kA$

实际上可以更进一步,用测试数据观察一下,会发现$kA$中的向量基本只涉及原始A中的至多两个向量的约减,并且系数是1或者-1。所以用贪心的思路去搜其实可以找到一个$A$的行向量置换后的结果,也就是可以找到一个$PA$,这是一个更强的条件

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
from random import *
from re import findall
from subprocess import check_output

def flatter(M):
# compile https://github.com/keeganryan/flatter and put it in $PATH
z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]"
ret = check_output(["flatter"], input=z.encode())
return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\\d+", ret)))

N, n, q = 1024, 60, 2**521-1
F, Fq = Zmod(256), GF(q)

with open("tedious", "r") as f:
tedious = eval(f.read())
α = Matrix(Fq, tedious["α"])
π = Matrix(Fq, tedious["π"])
mat = load("mat.sobj")

# σ*A+kα = π
# find αr = πr = 0

NN = α.stack(π).T
T1 = block_matrix(ZZ,[
[1, NN],
[0, q]
])
T1[:,-120:] *= q
T1 = flatter(T1)

Ker = []
for i in range(136):
Ker.append(list(T1[i][:256]))
Ker = Matrix(Zmod(q), Ker).T

NNN = Matrix(ZZ, Ker)

L = block_matrix(ZZ,[
[NNN,1],
[q,0]
])
L[:,:136] *= q
L = flatter(L)

A = []
for i in L[:80]:
A.append(i[-256:])
A = Matrix(ZZ,A)

#search for all A(using greedy)
def check(v):
if(all(i >= 0 and i <= 256 for i in v)):
return v
elif(all(i <= 0 and i >= -256 for i in v)):
return -v

def find(Ker,x):
x = [i for i in ini]
while(1):
for vi in x:
for i in Ker:
xi1 = check(i + vi)
xi2 = check(i - vi)
if xi1 and xi1 not in x:
x.append(xi1)
if(len(x) == 80):
return Matrix(ZZ,x)
if xi2 and xi2 not in x:
x.append(xi2)
if(len(x) == 80):
return Matrix(ZZ,x)

ini = [check(vi) for vi in A if check(vi)]
AA = find(A,ini)
print(list(AA))
*MT

这一步比赛中我完全没有注意到,直接导致了不知道该怎么恢复$A$的顺序,并且由于最后一步是需要求解s中向量的和而不是顺序的s,所以直接导致了我认为也许可以在A顺序错乱的情况下解决error_work部分,因此整个思路就跑偏了。

而现在看来,其实连题目名字都对这个做了暗示,只能说这波考虑的不是很周到TT

而之所以能用MT主要在于tedious_work部分里其实大范围使用了randrange函数:

1
2
3
4
5
def tedious_work(A):
α = random_matrix(Fq, n, N//4)
ε = matrix(n, N//4, [i*randrange(0, q) for i in α])
σ = matrix(Fq, [[randrange(1, q) for i in range(80)] for j in range(n)])
open("tedious", "w").write(str({"π": list(σ*A+ε), "α": list(α)}))

而对于$q=2^{521}-1$这种数字来讲,这样的randrange(0, q)基本完全等价于getrandbits(521),因此如果我们能求出$ε$,就有60个521bit的数字,就可以利用MT通过预测随机数的方式得到$σ$了。

而求解$ε$并不麻烦,回顾等式:

我们现在有了$kA$,那么我们求$kA$的右核$M$,代入就得到:

然后解矩阵方程就有$ε$,之后就可以通过MT预测随机数得到$σ$。

这里预测随机数的话,我用朴素的建矩阵方法会发现由于比特之间线性相关性很强,至少要用30000多bit的输出才能使矩阵的秩达到预期的19937,而这样内存会直接不够用

问了下hashhash师傅,又得到了一个有力的新工具:

https://github.com/icemonster/symbolic_mersenne_cracker

而现在我们有了$σ$,就可以恢复顺序正确的$A$了,粗暴一点直接对下式逐列做LLL即可:

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
PA = load("PA.sobj")

PA = Matrix(Fq, PA)
PA_Ker = Matrix(Fq, PA.right_kernel().basis()).T
X = π*PA_Ker
Y = α*PA_Ker
K = Y.solve_left(X)
k = []
for i in range(n):
k.append(K[i,i])
print(k)

############################################################### MT predict
go to python and predict MT :)
############################################################### MT predict

states = [113704197, 3405842530, 1738689478, 703229539, 2907259502, 1773213255, 4259193140, 2328997110, 2326382620, 3539943450, 3943473704, 1640519491, 1875870865, 2731501447, 4209819181, 3449883535, 3523992081, 3280171865, 2416845087, 2151403870, 693081970, 1747115758, 4015945850, 3686334481, 898499801, 4190457978, 3787813964, 3258218099, 3437965753, 1878250724, 3189476074, 1152476894, 147834339, 2769430677, 3511032479, 3567924279, 2161471426, 563308943, 3446408078, 1949971313, 1895962308, 3707951421, 968721904, 252441955, 2533651660, 2889128006, 1721763532, 2505823299, 458331240, 2059589053, 64385284, 4029357042, 695109338, 744440358, 3519688222, 2361161993, 3223663686, 2010594546, 3958688671, 2291905952, 3926524336, 2011139757, 461769836, 3114896752, 2282936557, 1927285746, 2582255350, 504168956, 4113181790, 848941762, 383163494, 1372255865, 3496580772, 2692443861, 3389749948, 498352369, 748459956, 3389041382, 141074870, 1632758136, 3219470486, 126558810, 1031061639, 2672864696, 48240402, 2704206234, 1425068775, 3265363748, 630960765, 3819353836, 1858506649, 485318072, 4128742296, 3376811318, 4204655629, 1286398000, 2303971794, 4274435326, 4044081550, 1715823135, 132631825, 3152223805, 2583497918, 1635027483, 3339956668, 707057445, 3980699204, 614764316, 1346718391, 1135939959, 2997914131, 4051263902, 1963572188, 770507588, 3909567052, 2091058219, 2543156465, 3842371252, 3443677424, 759282030, 2889909779, 1368851309, 305191756, 1858852750, 554329976, 3904036123, 2901653875, 2741469407, 2572249766, 1246238357, 659145741, 190685166, 3612959518, 640691503, 1185217803, 1009848496, 3206611783, 2894535678, 3453033501, 289230470, 1372089846, 1049152746, 2850741310, 984661882, 611884565, 1236657355, 3343527827, 2548951125, 562791145, 2252848045, 3105367880, 2712522865, 2479258764, 2986877450, 3601398564, 3662538540, 3275126554, 2940194474, 1356516733, 4044042721, 1494897675, 1989984303, 1097151926, 4221219684, 1212544909, 3340394958, 1390514300, 1549503887, 2581775858, 2545827540, 2645302457, 230521227, 3196138321, 2625674622, 79454347, 187896698, 2008836319, 1045267458, 1829322640, 4025973981, 3790962910, 283254001, 2623533575, 122212170, 1759345544, 869521827, 825919923, 486969567, 78939622, 2861038139, 1135095820, 2180896951, 900573089, 2804379345, 3626010865, 1053464390, 3427238220, 2692890127, 949965100, 2587630194, 2356494570, 1622890994, 986294457, 4244918160, 617700961, 1624977147, 2716699722, 2078770881, 1002097877, 244885836, 2443012853, 2039552484, 4171906420, 2427771544, 1305324504, 2724020235, 1036098721, 3919115037, 993285859, 386235749, 1258147194, 610050676, 3012646137, 2305189066, 1178414969, 3302542440, 1462463223, 1437498692, 3668103437, 1084808916, 309279283, 4017505061, 1558248353, 423359063, 4244733362, 616039082, 2102560308, 1060727767, 1920662732, 358907463, 3396088680, 903551662, 868558723, 3212315449, 2519349944, 1503499107, 2102219311, 3449942920, 669316525, 2108323918, 2708665195, 1941048760, 583680212, 3424787423, 2232015555, 2054145795, 242750178, 3896737257, 1467962784, 970382615, 1392558681, 3881466100, 2903195184, 3585586116, 1914526073, 2106370747, 1008444182, 2107010937, 2822188700, 1218447381, 2308375528, 3369742794, 2975504770, 4176851601, 67514816, 4246377398, 1734425751, 1993987051, 1145805899, 3244559845, 2521286868, 541117045, 721746299, 3298483091, 491071222, 1354933102, 2956619599, 1199597464, 3193364044, 3668585273, 200554677, 972726751, 2203882536, 3485522382, 2761802839, 3754978098, 165615557, 322534410, 3524217767, 4138073568, 2261377656, 4006747923, 109290994, 2456757773, 2374256574, 3232001613, 3564455680, 1701870507, 2377668333, 1216762358, 553166470, 4133793648, 2938687008, 3815389598, 2231853860, 3308357816, 515681335, 2826361049, 288633911, 110468545, 3265849311, 3852434959, 1231187782, 361481132, 584104453, 1935867088, 4149367251, 3831702086, 1203733277, 2899033791, 146772292, 2887208072, 3963017011, 3233095710, 3600173778, 1306987150, 390355547, 862238214, 3220269886, 2826165734, 689420894, 138511293, 1327820607, 265976988, 3864481874, 1774854365, 276867882, 2298473905, 698421415, 388689242, 1038955726, 3712967142, 2661024048, 4236026832, 1237739677, 4055165262, 534625863, 1489376830, 1800306875, 3698762430, 3777224699, 3234261312, 322143627, 1816432874, 1274393877, 812128958, 3249283852, 3740153121, 99828532, 678084661, 766588687, 387426792, 987971056, 2080859085, 850637292, 1277972870, 188018627, 2394503743, 2315476470, 1565011923, 1941074311, 1179787099, 482261965, 835090610, 1026182337, 530973140, 3201248099, 288945328, 2552958881, 2737411289, 617540214, 1987197723, 2597866739, 1229316798, 636632825, 3759065119, 2051062165, 1090249666, 4012867151, 3997281726, 1891614046, 1950467577, 1896564800, 2803835300, 3606368644, 257560555, 3883205059, 664635385, 4102706448, 622545284, 3280864106, 293013878, 1127325978, 3215983960, 1146222004, 3326539387, 808949477, 3970628609, 4007212270, 2711477502, 557726083, 766381908, 33900284, 932748148, 1121083738, 4272167901, 466227150, 1505452928, 1528845019, 2263605533, 1016244607, 3237061456, 3137273984, 4211330922, 1155964522, 1608938084, 2887620568, 2662588350, 1201565218, 568530275, 2678380208, 3359503459, 3144725110, 814896638, 1064850116, 1483772157, 2568601930, 541715956, 2063836765, 2016359752, 3728066075, 2254054776, 722016621, 741878938, 2558272354, 2808723788, 4234530153, 2125747501, 2704729045, 2113451904, 3332283037, 1208922003, 1310310684, 557110487, 1171236916, 1135441796, 3086182596, 181993156, 904442790, 2096301594, 3148947917, 547059118, 2676365459, 551054518, 1402555326, 1266743827, 966157584, 1462709454, 1044422747, 1816623887, 1723907402, 3680143765, 3729225582, 4137182800, 1540646791, 1904561630, 4070808312, 2453054379, 2140927760, 1460445742, 16529247, 311847522, 3767018970, 660938106, 1235032574, 2993757301, 1334679238, 1421661735, 3365436073, 4096075739, 1013195725, 755997768, 666263898, 1909896304, 3251310335, 3999215317, 3302976019, 3547292488, 3966102960, 1860144301, 2420524501, 4198383718, 364183848, 813072812, 165238552, 1286095762, 2406680229, 4139882913, 2593781524, 2461772957, 3516662592, 1468160566, 1468596495, 1290505617, 680659494, 1082427874, 3220637159, 599428397, 2343433113, 2528532716, 3311188194, 488997170, 3504561095, 97864554, 2912302105, 4221852521, 2908477548, 940703408, 439839216, 896505182, 1252814322, 1901262143, 604086101, 159852464, 3568973474, 3821487860, 623098514, 202248458, 2977078642, 4036934666, 1549547455, 3422386820, 2938814110, 2640881906, 2271464353, 3641908765, 3373579173, 2759933980, 2957563388, 1862384250, 3833642986, 714120541, 38008176, 823996869, 3512767789, 245085003, 3871751583, 816496606, 997537973, 597244106, 1948340722, 1142655576, 3213975398, 3177419168, 1277075442, 2836191462, 1836238758, 2631533053, 2398455289, 589980987, 102662424, 4050080940, 2606072212, 638082255, 3821379936, 1855702237, 141488036, 790011767, 2814221285, 423059338, 1324669488, 1772067999, 929474842, 3439201681, 1472574624, 2524204217, 991362400, 60046905, 897384794, 4064258414, 1628707668, 644418391, 3844473927, 802859186, 2748442866, 2501688702, 693109486, 1060328162, 674456370, 2161128289, 1739588708, 1790254588, 3158300972, 3677273706, 4036870155, 1785921241, 1010936739, 1815361842, 2442375985, 278516160, 4182906499, 2505615705, 2501155191, 2687203272]
states = [int(i) for i in states]
RNG = Random()
RNG.setstate((3,tuple(states+[396]),None))
σ = matrix(Fq, [[RNG.randrange(1, q) for i in range(80)] for j in range(n)])

from tqdm import *

NN = π-K*α

A = []
for i in trange(256):
L = block_matrix(ZZ,[
[1, 0, σ.T],
[0, 1, Matrix(ZZ,NN[:,i:i+1]).T],
[0, 0, q]
])
L[:,-60:] *= q
res = list(flatter(L)[0])
res = list(map(abs, res))
A.append(list(res[:80]))

A = Matrix(F, A).T
save(A, "A")
error_work

现在我们有了顺序的$A$,我们也就拥有了20个下面的实例中的$t_i,a_i$:

e的误差数量少,但是误差值是$F_{256}$下的随机值,这显然是一个将$a_i$作为生成矩阵的线性码解码问题。

我对编码了解的并不多,不过很容易注意到两个事实:

  • 1024个方程中只有22个是错误的,所以随机选520个去解方程得到s,这概率也并不低,几百万次就可以

    可以这样简单测一下:

    1
    2
    t = comb((1024-22),520) / comb(1024,520)
    print(int(1/t))
    1
    7523285
  • $Z_{256}$完全可以转到$Z_2$下做decode,计算量减小的同时,偶数的误差还会消失,相当于误差数量会变小

    同样可以测一下,既然一共有22个error,那么预期中放到模2后会减小11个error,所以我们能定位11个error的位置,从而减小选到error的概率,此时期望为:

    1
    2
    t = comb(1024-22,520) / comb(1024-11,520)
    print(int(1/t))
    1
    2920

    可以看出需要的次数就少很多了

所以一个很自然的思路就是:

  • 先对每个码字在模2下decode,这样可以把奇数的误差定位,然后从备选列中剔除掉
  • 之后在$Z_{256}$下剩余的列中随机选择520列去解方程(这样做是为了增加约束),有解的时候就得到了s

在模2下decode可以直接抄maple在Grey Cat The Flag 2024 Qualifiers中的调用,由于模2下期望会有一半的奇数误差会消失,所以可以把error weight设置的低一些提高解码速度,之后就一直从剩余的方程组里抽一直到找到解就好。

不过实际上手会发现,解512x520规模的$F_{256}$下矩阵方程也要好几秒一次,所以要加点多进程才行。

其实还是相当慢,所以还是按预期解从$Z_2$下decode往上lift最好,但是我真的不太会

应该都不能说相当慢,实际上是巨慢,尤其有一个$F_2$下error只有6个的,预期要roll 20万次,所以我实际上偷懒没跑这组而是直接用了hashhash的数据XD

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
A = load("A.sobj")

############################################################### collect codewords
C = []
for i in range(20):
C.append(vector(F, A[4*i:4*i+4].list()))

from sage.coding.linear_code import LinearCode
from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm
from itertools import *
from random import *
from tqdm import *

def My_decode(Generator_Matrix, Codeword):
######################## ISD decode in F2
G = Generator_Matrix.change_ring(F2)
CODE = LinearCode(G)
D = LeeBrickellISDAlgorithm(CODE, decoding_interval=(5, 15))

s = Codeword.change_ring(F2)
res = (D.decode(s))
e = (res-s).list()

error_ind = []
for i, ei in enumerate(e):
if(ei == 1):
error_ind.append(i)
return error_ind

error_inds = []
for i in range(20):
error_ind = My_decode(mat[i], C[i])
error_inds.append(error_ind)
print(error_ind)

from multiprocessing import *

######################## roll
def roll(_):
ind = sample(list(set(range(0, 1024)) - set(error_ind)), 520)
temp_a = mat[i][range(0,512), ind]
temp_c = Matrix(F, C[i])[[0], ind]
try:
s = temp_a.solve_left(temp_c)
print(s.list())
return s
except:
pass

for i in range(20):
error_ind = error_inds[i]
with Pool(processes=4) as pool:
for _ in tqdm(pool.imap(roll, range(10000)), total=int(10000)):
if(_ != None):
break
1
2
3
4
5
cipher = AES.new(md5(str(sum(s)).encode()).digest(), AES.MODE_ECB)
enc = "af3010a3de0fa968c38f421f2857d6c60caf9a6ae1023e9d04f253e1d5fb8038fddf26f7cc976fadbb2df12ef549d1fd"
print(cipher.decrypt(bytes.fromhex(enc)))

#n1ctf{ISD&LLL_4re_bo7h_v3ry_pow3rfu1_t00ls}

方法二

有意思的是,sage的random随机数似乎也并不安全,其使用的随机数主要是基于MT的python random和基于gmp的c random。而究竟使用哪一种似乎和以下两者都有关系:

  • 是矩阵还是向量
  • 使用的环是什么

这一部分可以做如下测试:

1
2
3
4
5
6
7
8
9
10
import random
SEED = random.randint(0, 1337)
N, n, q = 1024, 60, 2**521-1
F, Fq = Zmod(256), GF(q)

set_random_seed(SEED)
print(getrandbits(521))

set_random_seed(SEED)
print(random_matrix(Fq, 1, 1))
1
2
5944058836160505616155866937005287978210040077123457746556810859056754156581041151236899945171255465561118925474653412955903593045941410134996821295584866556
[5944058836160505616155866937005287978210040077123457746556810859056754156581041151236899945171255465561118925474653412955903593045941410134996821295584866556]

以及:

1
2
3
4
5
set_random_seed(SEED)
print([randrange(0, 256) for i in range(10)])

set_random_seed(SEED)
print(random_vector(F, 10))
1
2
[188, 170, 178, 103, 61, 228, 17, 94, 56, 168]
(188, 170, 178, 103, 61, 228, 17, 94, 56, 168)

这两个测试说明,对于题目中的:

1
2
3
s = [random_vector(F, N//2) for _ in range(20)]

α = random_matrix(Fq, n, N//4)

sage均使用的是基于MT19937的python的random,而我们拥有$α$,并且比特完全足够,因此可以恢复$α$前对应的随机数状态,并且往前回滚得到$s$前的随机数状态,然后直接预测$s$就可以了。由于s使用的是randrange(0,256)所以并不好预测究竟需要回滚多少个状态,所以简单爆破一下看能不能解出flag就好了。

而对于:

1
a = random_matrix(F, N//2, N)

似乎就没有使用python的random

exp:

1.用$α$的前60个值,和方法一的第二步MT一样恢复出$α$前的MT state:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#https://github.com/icemonster/symbolic_mersenne_cracker

from z3 import *
from random import Random
from itertools import count
from time import time
import logging

logging.basicConfig(format='STT> %(message)s')
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

SYMBOLIC_COUNTER = count()

class Untwister:
def __init__(self):
name = next(SYMBOLIC_COUNTER)
self.MT = [BitVec(f'MT_{i}_{name}', 32) for i in range(624)]
self.index = 0
self.solver = Solver()

#This particular method was adapted from https://www.schutzwerk.com/en/43/posts/attacking_a_random_number_generator/
def symbolic_untamper(self, solver, y):
name = next(SYMBOLIC_COUNTER)

y1 = BitVec(f'y1_{name}', 32)
y2 = BitVec(f'y2_{name}' , 32)
y3 = BitVec(f'y3_{name}', 32)
y4 = BitVec(f'y4_{name}', 32)

equations = [
y2 == y1 ^ (LShR(y1, 11)),
y3 == y2 ^ ((y2 << 7) & 0x9D2C5680),
y4 == y3 ^ ((y3 << 15) & 0xEFC60000),
y == y4 ^ (LShR(y4, 18))
]

solver.add(equations)
return y1

def symbolic_twist(self, MT, n=624, upper_mask=0x80000000, lower_mask=0x7FFFFFFF, a=0x9908B0DF, m=397):
'''
This method models MT19937 function as a Z3 program
'''
MT = [i for i in MT] #Just a shallow copy of the state

for i in range(n):
x = (MT[i] & upper_mask) + (MT[(i+1) % n] & lower_mask)
xA = LShR(x, 1)
xB = If(x & 1 == 0, xA, xA ^ a) #Possible Z3 optimization here by declaring auxiliary symbolic variables
MT[i] = MT[(i + m) % n] ^ xB

return MT

def get_symbolic(self, guess):
name = next(SYMBOLIC_COUNTER)
ERROR = 'Must pass a string like "?1100???1001000??0?100?10??10010" where ? represents an unknown bit'

assert type(guess) == str, ERROR
assert all(map(lambda x: x in '01?', guess)), ERROR
assert len(guess) <= 32, "One 32-bit number at a time please"
guess = guess.zfill(32)

self.symbolic_guess = BitVec(f'symbolic_guess_{name}', 32)
guess = guess[::-1]

for i, bit in enumerate(guess):
if bit != '?':
self.solver.add(Extract(i, i, self.symbolic_guess) == bit)

return self.symbolic_guess


def submit(self, guess):
'''
You need 624 numbers to completely clone the state.
You can input less than that though and this will give you the best guess for the state
'''
if self.index >= 624:
name = next(SYMBOLIC_COUNTER)
next_mt = self.symbolic_twist(self.MT)
self.MT = [BitVec(f'MT_{i}_{name}', 32) for i in range(624)]
for i in range(624):
self.solver.add(self.MT[i] == next_mt[i])
self.index = 0

symbolic_guess = self.get_symbolic(guess)
symbolic_guess = self.symbolic_untamper(self.solver, symbolic_guess)
self.solver.add(self.MT[self.index] == symbolic_guess)
self.index += 1

def get_random(self):
'''
This will give you a random.Random() instance with the cloned state.
'''
logger.debug('Solving...')
start = time()
self.solver.check()
model = self.solver.model()
end = time()
logger.debug(f'Solved! (in {round(end-start,3)}s)')

#Compute best guess for state
state = list(map(lambda x: model[x].as_long(), self.MT))
result_state = (3, tuple(state+[self.index]), None)
r = Random()
r.setstate(result_state)
return r

def test():
'''
This test tries to clone Python random's internal state, given partial output from getrandbits
'''

output = [2052989026187628018505090216721349257452581944142415044520527283300574439605232693924109130927700026879802796798323130703768462662264638677972389236566564575, 5225453256971737388486294931922039723340310407624514585062950191132550635768693727698459978225483485890925297979009284845547716345384959943882275816157687522, 6384003021200443422209284938066284944669598755830743086665589025405179546034869584039261565027186461914605565757632351322204847925981744856258211161068962322, 1749535151849566187562576405003328739241590589609203380130002844778384115925449614939660420719072392543285487823449085629595737479050295300740318775147141579, 5028025320872348362619664669575352799437383176221191236696571007384660009171202139415054134818787096610593718145741391462358687204496779816506856719141822655, 496105389179110910629571770916587634389042066650650257984425579874269918093468333674503357907872779356736656387751255169742066622514477356752574103752131907, 3436855010723926113914942417231300525946855375567023250635707341579460565380653848367023918454841973305084860125309974180861555605508772341646716195399365641, 6126584195256719540568595688171701520258384637422147995403164340188577964266020306172506706376147755631534578364425038386201967414344847686467113226605035647, 980463459392690589018511996961588727033831901561920491880496428802031123124266300366385644958771021910396372842006537733114158691781047162064456565268039423, 3652411206440878868321893768049493042384908161622024948617835677764964851294519032229584748784200434359115515336005141988750075009657556840833146078021874926, 2174879036711363551252583514620689099374871765443068829351645435692473845036078497382453747762822086149466006744940455868715607363213427160625441871341462395, 5057161665517951196188775375262157617415164154804898875881631910813336506375890993210100033195636519929285472203830569798770975843515247529830732301265811610, 3306354345456324305074016662906845877163348338433268040446425605369588703300245563982934380844167018438270650903252227989642100951223267144417336415457798793, 2395295827790551011206890233834169858780101019556800625387218301201488293147130548238081822267669177571367238053707203742360784411688050311559279681980986543, 3006440442470261829769737273401992023902498352130211793681154933115235093996373416329694168374953860876342908337466572761808496026203125027138992629106731845, 1153335005948746880307780666251566051703622919983097397853073421335999214278284948151883340746104177260976555660395124646968377361398057860351000455659172753, 1713042247455350230980953003394073696438285832334658730294685528889059080601549339420898350208749049716932962821610503236722535443046716897749780581289914827, 6754872611146772982321539683086146839023334463431896549539154850577425062259371535865000216871632400150813401709488403962840438930093822109433522248076335453, 6287767710864953400162108162359797621683058548057219086424193941013508335646817903498303763266852729734701262490912770181115559489358156868483173973970896500, 277222994371822706011862250140774279279717760500323019954692225078469794747203189591101712531432953672193933736201841583286416558354027298499084319294266412, 3417483291875129256979825075566667645256166558484633170457014974679182788714367016926202779878176844493099202145254197167929477242077894628242444310915435398, 1085574083993420275607687913329013813184696072773453652882238989708601326302312337097542482875606073431406521335570070881523196767102663840651591897065521451, 5824524783001727209410550431451051249153129904450694782169510505422548986765068364258945827721962400963712050419134221789012348504943171015015286195863741990, 6601704560909354252211567773611704159084174986033676854122473607988733744133599808617417824367662776815562925495656657077610026802238706624802394508354382148, 1778728784912759795362720287833831788990118630684781280373253516908530206654109738328107440719393589661937340024693100223247040455793889248357242927688249892, 6416915812588224445664782904627808566308128227543703756173589465941343171343329178775719353076596703967239413984077128263762103257171686055811444891645058825, 5739610032587855032938141208882547321527220335919128940513766189887752273496886645979114098327083944538653971085936369596331580269970350655792421403911218655, 2063855308502428822052864418394676238099820881407216754278816888071173792037207936694253120891457529764314756926486324995043087252687982036705198813378915664, 3477014337875015781602614555329709730077743902336655810403582109365871797674415343416290352708164743041148302507372623483914816177500922432388906061331010874, 6482753687608143462975264728796511686801896699218076243699494447233075903361449747866927251714679260824592213324644920916464697213325172580450392013468313625, 1144732121561114538620960110896213703757595862303960780609679192419827034553160301395118859233329298864065526742315395530587230061978407308761087510969098409, 2663369250614584903359257073704180061042944465829120277084658626435685666314449604497330552008479082289591533430241478785954240332982496438448662087272856305, 1625503401877123118064587116015097162029645572178122120001601243566285131349626207724577697865342288922037055759546997159838046372090429869044438362780094305, 680862130832745355482990226054726660700744091327381718588096814032920534644088306118028565030883946615364836537820384219127268869142235593745558070963246041, 4014882414151152288278066287017219459517759804864469524435736300373136293076080399716126093409172228322667138734528238551437409733979711331332729319865312380, 4704422950875530532314436497542324322568368963516120007597805770848514388576922162359189592976527098266409570948396449912366815182032739123169830920718240305, 690164231059595242495550826244944222832161585294669271266123700025314593488116364307091231217508692332713273666595763460533614284962864262311953014474100379, 6785829762856450361030167999327180879044601158002269665141528541227641113240929279463596507125747748828112084379276365843303538716230262095861080100351754036, 6779411395854639364180412834268053789798254161508878815420901542082669783279757284379191439433216856901462566105364399347339857409897364054612473287336684229, 5200486327896911752627279013153346424456647268087509562785746212643962947789386193923551262593722145785625094327307036507781725614475280984248955406218315718, 6766018115505863233496488437504459564113553032701552228566296851598728108852369292454441019867167767198684677471103842991965444612399832466426762140833990202, 1857754167234108369058884687356671100191937657538963073611935069599963008145512071283477417736344612203774963433585165206676941234180263371794308454523989258, 6218380854447481926832586680866881879231599650578367203954021608556581539882097533150164512127332627836132629103311365902275901798241841875282176216854372386, 4484250341955282540982557066029960403557526151445828782762206036414084714109807995562348007095479519319978490833884948660962896859419673330915736283143119293, 5719518665799717540922616548756376704294224287680684753299589462494633283400267383560646499107229160421788984246235644208190094197129677382137279191626345567, 6183544838511811934598450247658473506717449889422546720457877419017221164143542485286136887936019942488983081115288675646150516467627345851970793260108794248, 4060259625864440523893329913437385815330396229854633674900837462639601270822525680439043588461389374062208192344001519699398183502957051281689538918582785802, 4674255678026139884783381633770087579505974819398209649510660042794673596753605680540279361204472325548871131655347722123765127705717766800550489928590118583, 4235305174354877875880908721407722693409603927061930442201385805259206491962626609891620509618680662074877029489958861063726108784357485910285094561525579418, 1304482879046737936250592217446487940668006269296100323856207643321946575384121112118644269963713452266947486055748791840597314419623478449556227943272046751, 5723133662393454897727214372311054844979375357613580104308566445799906123427550619290628869605832625649167487752674788026571792245384816910716687617609324597, 6690869337372358677787805305676510474430932152287453356690736391174276385319926576449243708302298262160338357175238351080196044336828436713453500956276986912, 1709148516176100595454198345227647770776132068617957305207797613284696740095278846956146899436846161083141396382322084258921974790018204061260478170839382429, 4596839062486185169691326142435396173701999982790472119509678270254374603237887252036067253657432053010005919035531672204949754186386950770753054022640122023, 4284033026192974690107958342383445955597787488718148718914401336986762283353122956474851504895403044034780250657199691622138838949395491585859922179871223880, 4407596618033695273966500201194728131045986855339262025197711076433716644886501682901785057973164763471419390429811949642266673464590420468022335170603532947, 1245174090116826165252009130854025626244787263188227463552747207763429695036678627645359427139881800183870064022547165863193854107493333053578705645112218474, 5252075015773147287797948406007229837831033114960436353240449428563534907880527872801125844353143910297718695315389930603134648587470649842791016137936418152, 5985509734129310460156410707722925029030939626269875091364071549162048868371903545512866235224306730924941031773042663444889701280634369335066845011589227199, 3080785963946069150817641927843563289944890563483038488395920525403208821802200181379991729951535386499548811296451709870981902091035283243521924070732157750]

ut = Untwister()
for i in range(60):
random_num = output[i]
for j in range(521 // 32):
temp = random_num % 2**32
#Just send stuff like "?11????0011?0110??01110????01???"
#Where ? represents unknown bits
ut.submit(bin(temp)[2:])
random_num //= 2**32
ut.submit(bin(random_num)[2:].zfill(9) + '?'*(32-9))

r2 = ut.get_random()
print(r2.getstate())

logger.debug('Test passed!')

test()

#(3, (2695351630, 1922033548, 3434285234, 1544004455, 1971679449, 2774743117, 3568751734, 1170380852, 1379196785, 1939082526, 2609756861, 3442274255, 1514280443, 2328412430, 2930371449, 2709335402, 3045974100, 1095250868, 29188524, 1282079643, 1748476443, 1066105964, 2733262304, 3401683597, 3103068408, 756269773, 329534395, 3919968778, 1340762899, 2811215679, 2496174671, 282861806, 2709945287, 2257145940, 2513147842, 3017095841, 1525533007, 3901083136, 881396069, 4101418280, 3117510379, 664979225, 1184559110, 557650144, 2550739260, 2838292721, 3627246855, 2589687440, 1495367117, 2576251097, 499262401, 4179172825, 2367686693, 2360776332, 209458381, 4147883114, 3396842125, 3786537214, 487568147, 2695851970, 2907500362, 975567326, 2458576665, 890584127, 577880192, 1993936114, 3156920383, 3315678592, 3061729594, 1162861667, 145048345, 4018945859, 3007415521, 3918838031, 3720821775, 3987846803, 811460519, 3161180265, 625437996, 477986559, 1555396672, 2133352784, 1747342437, 3666573972, 1365391887, 3102897853, 3250112758, 538062034, 2511466698, 622265354, 2871802720, 2845479676, 375152243, 3169670953, 191187436, 2991608187, 1385066376, 460368470, 2402581268, 952887140, 700309987, 381635554, 4063255635, 1021828086, 585091460, 4109272880, 1454999395, 4148434546, 2767540010, 2660853287, 3788075980, 2555726211, 3245823338, 3683005854, 958913863, 2713105594, 4196842608, 1465195517, 2635158305, 1420506679, 334853929, 3122754632, 2077259078, 2419490021, 3713338924, 133052797, 806303692, 1417535111, 1840829159, 145342917, 1480485299, 2798325123, 805412851, 1864526757, 880431652, 1105737777, 2536413707, 3080713391, 386924434, 3862566445, 2474880484, 4267123879, 389996517, 663377419, 1833262401, 3348724287, 3163891885, 524987442, 148925713, 2199399462, 3023817677, 3591368111, 2073886928, 1701801386, 2462126806, 2846628474, 2006935973, 1226649139, 3942930853, 3591196289, 829918901, 2161011364, 3496545202, 4123615426, 38981881, 3976538818, 2966074173, 382108347, 1609211023, 731344784, 615384328, 3571633366, 3739560838, 311792144, 357755121, 398715352, 395325949, 3224565755, 1144699515, 1234027576, 2541458991, 1936013031, 2544749596, 1053917138, 3829274346, 3601012612, 2608608732, 3590342851, 1673805541, 307531817, 2128493756, 3972876403, 1119289067, 434260810, 3431723586, 3389990349, 1964588337, 3714264779, 3583745038, 2225177744, 1652794835, 3717726474, 3748734579, 4214809352, 2967377755, 3781580863, 2316674100, 3501596442, 1968584574, 4149533253, 287041241, 1825446649, 3375573761, 2290055766, 4019478620, 4240249413, 366837734, 4247442960, 3883261001, 1657732020, 2860896929, 2756884805, 2128518208, 3160326168, 1637043802, 2415236233, 3619732061, 1700240223, 1790264898, 2779684519, 46960106, 1399559342, 1025546687, 97943525, 4049004778, 2608551088, 345857, 1090754829, 2612513527, 940959874, 2550801041, 2356638469, 3282897446, 4058560059, 3662430984, 1080626705, 82219622, 601861194, 3443334643, 3907276605, 2130019402, 3704586187, 3545234472, 796974359, 1479422678, 4261725354, 1446892727, 3762923341, 443374502, 4017158958, 3657999925, 3064838547, 200910956, 2943067376, 1102158119, 493064078, 1916229505, 3648028538, 4112706839, 31003100, 2240639338, 3553806242, 3993988596, 973881269, 3371788669, 154325011, 4246683748, 1680749770, 2940357623, 3342155435, 1857799688, 3102929857, 2180772957, 2457056253, 1565671423, 752356380, 491419859, 161553999, 3104702045, 316450207, 1727941732, 1727384240, 4021066939, 1326662785, 378855826, 1687197186, 4094819706, 1979724537, 167949249, 1194605310, 1857749288, 1352722956, 3940093956, 1911958716, 1579356568, 3710855087, 2321004874, 3522796444, 1742617775, 2409299307, 1532201350, 2479894877, 3006495102, 2997713743, 2329795244, 2245290913, 3825156457, 4081201570, 3589106763, 1965152372, 2605880159, 2879378407, 2702002615, 2840755118, 2149936893, 1093503770, 116365721, 1787229610, 2750488345, 2565698802, 2145430013, 4294584394, 204085151, 2174636229, 3140251174, 2698991393, 1282497103, 3234172194, 3005695031, 1703056711, 4201744590, 2432616404, 2395214101, 1368140699, 3834324503, 527998606, 619354998, 1499560365, 3118597689, 1132038758, 1140985482, 1465112585, 2663864350, 3804111686, 3821903933, 2060217054, 623765990, 2695673791, 2894717969, 2854359345, 1490209382, 1480221386, 2661140567, 2800104837, 3829991940, 2119283425, 3780763340, 1972124184, 750187038, 2166699281, 1733185634, 853630604, 3138298595, 1146150252, 3889993817, 831667601, 3469180435, 1822031579, 1635272530, 2108618632, 2385640880, 4011742384, 2811145464, 1025710081, 4168474162, 1667481551, 1928764243, 3205524955, 3088609896, 103133477, 2111904259, 968563202, 3026287000, 3890106396, 1161986845, 1405689645, 2811250603, 4143581466, 1019916766, 2700566049, 3746584683, 3605347392, 819182452, 3581693404, 3037287253, 1436448777, 3397905833, 2816662728, 923624196, 4086396771, 168910861, 3269200513, 2416914148, 3536145407, 71109343, 3307423015, 4212940886, 260844613, 2618967116, 2257891982, 2661096380, 1942630262, 61352998, 2810323365, 3418782676, 1387676775, 3501234354, 4085894422, 2012613408, 2387049773, 753189678, 2894357270, 456730381, 3104330676, 3061793182, 776353181, 4016986299, 2774792199, 3466903569, 3304601777, 4294685334, 1561660819, 3038024764, 1817514750, 3768248971, 1812666977, 4206697533, 2662688175, 1229262173, 2972369904, 4138621734, 1015377946, 2651562555, 268255977, 3252122337, 1621021176, 2994730872, 559931834, 3988579176, 3567691983, 1930674231, 2218383326, 758788884, 910208449, 227817632, 2140599685, 3548929815, 2587591999, 3580039418, 1872428683, 701406125, 4288602909, 1109645047, 1397038574, 2576598599, 586000901, 2693205802, 152821105, 2557672927, 2165199135, 1482476870, 1144667446, 3796957272, 182521958, 3425668252, 1367303991, 1303438183, 3798174016, 3822328448, 2174253407, 368330786, 123594742, 1208148383, 1769908846, 3062152568, 1874539716, 4098588639, 1184714779, 2489698445, 3909685808, 1928812454, 3605420887, 4111625005, 3601167612, 2365741840, 1767141708, 572895792, 2249632076, 4291418450, 603542283, 2506946516, 3132493203, 235891852, 2035908962, 2962949323, 756732284, 1229852751, 163244976, 4117722390, 2204154201, 2211522886, 1137023330, 694949872, 16637714, 167503308, 3680251840, 2097279770, 3496392499, 3178068824, 3118729426, 3137404850, 3646384420, 3444927241, 2182874045, 415700967, 4278153892, 3578893031, 415285993, 1910390682, 443081739, 4009368874, 3216674839, 2732429792, 1801899246, 884417585, 2683393468, 2168835935, 567679007, 2675310920, 3244164342, 948786909, 4049866703, 3763778347, 3994212229, 937179772, 682416950, 4237120584, 1314748325, 1011893987, 594451978, 2591572861, 3321773081, 1782732845, 1906672771, 3198375563, 2677553481, 2524341084, 3834072067, 1843752429, 2535045290, 3159920919, 3333512770, 2901497143, 255992028, 1329320485, 2705147800, 1648509016, 3063622090, 2994198416, 2054303692, 3202051646, 3658720183, 412326269, 1481252325, 2852045384, 253106637, 3226081928, 4263121751, 541226047, 2226732784, 938020060, 1949217059, 3270150900, 548921532, 2822626483, 3199026017, 3417519239, 3658562304, 2840731352, 3326593139, 60562367, 2609616202, 1639463440, 2922591920, 2626459952, 3751875818, 3985074014, 2918717822, 3453007911, 2602897826, 2633193513, 592359758, 2145325100, 1967291896, 392327774, 606203046, 2265885037, 3053206123, 3875079316, 2579332720, 1131140826, 247340200, 497676100, 3083051276, 396), None)

2.往前回滚,并逐个测试s进行解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
import random

N, n, q = 1024, 60, 2**521-1
F, F2, Fq = Zmod(256), Zmod(2), GF(q)

states = [2695351630, 1922033548, 3434285234, 1544004455, 1971679449, 2774743117, 3568751734, 1170380852, 1379196785, 1939082526, 2609756861, 3442274255, 1514280443, 2328412430, 2930371449, 2709335402, 3045974100, 1095250868, 29188524, 1282079643, 1748476443, 1066105964, 2733262304, 3401683597, 3103068408, 756269773, 329534395, 3919968778, 1340762899, 2811215679, 2496174671, 282861806, 2709945287, 2257145940, 2513147842, 3017095841, 1525533007, 3901083136, 881396069, 4101418280, 3117510379, 664979225, 1184559110, 557650144, 2550739260, 2838292721, 3627246855, 2589687440, 1495367117, 2576251097, 499262401, 4179172825, 2367686693, 2360776332, 209458381, 4147883114, 3396842125, 3786537214, 487568147, 2695851970, 2907500362, 975567326, 2458576665, 890584127, 577880192, 1993936114, 3156920383, 3315678592, 3061729594, 1162861667, 145048345, 4018945859, 3007415521, 3918838031, 3720821775, 3987846803, 811460519, 3161180265, 625437996, 477986559, 1555396672, 2133352784, 1747342437, 3666573972, 1365391887, 3102897853, 3250112758, 538062034, 2511466698, 622265354, 2871802720, 2845479676, 375152243, 3169670953, 191187436, 2991608187, 1385066376, 460368470, 2402581268, 952887140, 700309987, 381635554, 4063255635, 1021828086, 585091460, 4109272880, 1454999395, 4148434546, 2767540010, 2660853287, 3788075980, 2555726211, 3245823338, 3683005854, 958913863, 2713105594, 4196842608, 1465195517, 2635158305, 1420506679, 334853929, 3122754632, 2077259078, 2419490021, 3713338924, 133052797, 806303692, 1417535111, 1840829159, 145342917, 1480485299, 2798325123, 805412851, 1864526757, 880431652, 1105737777, 2536413707, 3080713391, 386924434, 3862566445, 2474880484, 4267123879, 389996517, 663377419, 1833262401, 3348724287, 3163891885, 524987442, 148925713, 2199399462, 3023817677, 3591368111, 2073886928, 1701801386, 2462126806, 2846628474, 2006935973, 1226649139, 3942930853, 3591196289, 829918901, 2161011364, 3496545202, 4123615426, 38981881, 3976538818, 2966074173, 382108347, 1609211023, 731344784, 615384328, 3571633366, 3739560838, 311792144, 357755121, 398715352, 395325949, 3224565755, 1144699515, 1234027576, 2541458991, 1936013031, 2544749596, 1053917138, 3829274346, 3601012612, 2608608732, 3590342851, 1673805541, 307531817, 2128493756, 3972876403, 1119289067, 434260810, 3431723586, 3389990349, 1964588337, 3714264779, 3583745038, 2225177744, 1652794835, 3717726474, 3748734579, 4214809352, 2967377755, 3781580863, 2316674100, 3501596442, 1968584574, 4149533253, 287041241, 1825446649, 3375573761, 2290055766, 4019478620, 4240249413, 366837734, 4247442960, 3883261001, 1657732020, 2860896929, 2756884805, 2128518208, 3160326168, 1637043802, 2415236233, 3619732061, 1700240223, 1790264898, 2779684519, 46960106, 1399559342, 1025546687, 97943525, 4049004778, 2608551088, 345857, 1090754829, 2612513527, 940959874, 2550801041, 2356638469, 3282897446, 4058560059, 3662430984, 1080626705, 82219622, 601861194, 3443334643, 3907276605, 2130019402, 3704586187, 3545234472, 796974359, 1479422678, 4261725354, 1446892727, 3762923341, 443374502, 4017158958, 3657999925, 3064838547, 200910956, 2943067376, 1102158119, 493064078, 1916229505, 3648028538, 4112706839, 31003100, 2240639338, 3553806242, 3993988596, 973881269, 3371788669, 154325011, 4246683748, 1680749770, 2940357623, 3342155435, 1857799688, 3102929857, 2180772957, 2457056253, 1565671423, 752356380, 491419859, 161553999, 3104702045, 316450207, 1727941732, 1727384240, 4021066939, 1326662785, 378855826, 1687197186, 4094819706, 1979724537, 167949249, 1194605310, 1857749288, 1352722956, 3940093956, 1911958716, 1579356568, 3710855087, 2321004874, 3522796444, 1742617775, 2409299307, 1532201350, 2479894877, 3006495102, 2997713743, 2329795244, 2245290913, 3825156457, 4081201570, 3589106763, 1965152372, 2605880159, 2879378407, 2702002615, 2840755118, 2149936893, 1093503770, 116365721, 1787229610, 2750488345, 2565698802, 2145430013, 4294584394, 204085151, 2174636229, 3140251174, 2698991393, 1282497103, 3234172194, 3005695031, 1703056711, 4201744590, 2432616404, 2395214101, 1368140699, 3834324503, 527998606, 619354998, 1499560365, 3118597689, 1132038758, 1140985482, 1465112585, 2663864350, 3804111686, 3821903933, 2060217054, 623765990, 2695673791, 2894717969, 2854359345, 1490209382, 1480221386, 2661140567, 2800104837, 3829991940, 2119283425, 3780763340, 1972124184, 750187038, 2166699281, 1733185634, 853630604, 3138298595, 1146150252, 3889993817, 831667601, 3469180435, 1822031579, 1635272530, 2108618632, 2385640880, 4011742384, 2811145464, 1025710081, 4168474162, 1667481551, 1928764243, 3205524955, 3088609896, 103133477, 2111904259, 968563202, 3026287000, 3890106396, 1161986845, 1405689645, 2811250603, 4143581466, 1019916766, 2700566049, 3746584683, 3605347392, 819182452, 3581693404, 3037287253, 1436448777, 3397905833, 2816662728, 923624196, 4086396771, 168910861, 3269200513, 2416914148, 3536145407, 71109343, 3307423015, 4212940886, 260844613, 2618967116, 2257891982, 2661096380, 1942630262, 61352998, 2810323365, 3418782676, 1387676775, 3501234354, 4085894422, 2012613408, 2387049773, 753189678, 2894357270, 456730381, 3104330676, 3061793182, 776353181, 4016986299, 2774792199, 3466903569, 3304601777, 4294685334, 1561660819, 3038024764, 1817514750, 3768248971, 1812666977, 4206697533, 2662688175, 1229262173, 2972369904, 4138621734, 1015377946, 2651562555, 268255977, 3252122337, 1621021176, 2994730872, 559931834, 3988579176, 3567691983, 1930674231, 2218383326, 758788884, 910208449, 227817632, 2140599685, 3548929815, 2587591999, 3580039418, 1872428683, 701406125, 4288602909, 1109645047, 1397038574, 2576598599, 586000901, 2693205802, 152821105, 2557672927, 2165199135, 1482476870, 1144667446, 3796957272, 182521958, 3425668252, 1367303991, 1303438183, 3798174016, 3822328448, 2174253407, 368330786, 123594742, 1208148383, 1769908846, 3062152568, 1874539716, 4098588639, 1184714779, 2489698445, 3909685808, 1928812454, 3605420887, 4111625005, 3601167612, 2365741840, 1767141708, 572895792, 2249632076, 4291418450, 603542283, 2506946516, 3132493203, 235891852, 2035908962, 2962949323, 756732284, 1229852751, 163244976, 4117722390, 2204154201, 2211522886, 1137023330, 694949872, 16637714, 167503308, 3680251840, 2097279770, 3496392499, 3178068824, 3118729426, 3137404850, 3646384420, 3444927241, 2182874045, 415700967, 4278153892, 3578893031, 415285993, 1910390682, 443081739, 4009368874, 3216674839, 2732429792, 1801899246, 884417585, 2683393468, 2168835935, 567679007, 2675310920, 3244164342, 948786909, 4049866703, 3763778347, 3994212229, 937179772, 682416950, 4237120584, 1314748325, 1011893987, 594451978, 2591572861, 3321773081, 1782732845, 1906672771, 3198375563, 2677553481, 2524341084, 3834072067, 1843752429, 2535045290, 3159920919, 3333512770, 2901497143, 255992028, 1329320485, 2705147800, 1648509016, 3063622090, 2994198416, 2054303692, 3202051646, 3658720183, 412326269, 1481252325, 2852045384, 253106637, 3226081928, 4263121751, 541226047, 2226732784, 938020060, 1949217059, 3270150900, 548921532, 2822626483, 3199026017, 3417519239, 3658562304, 2840731352, 3326593139, 60562367, 2609616202, 1639463440, 2922591920, 2626459952, 3751875818, 3985074014, 2918717822, 3453007911, 2602897826, 2633193513, 592359758, 2145325100, 1967291896, 392327774, 606203046, 2265885037, 3053206123, 3875079316, 2579332720, 1131140826, 247340200, 497676100, 3083051276]
states = [int(i) for i in states]

def backtrace_untwist(cur):
high = 0x80000000
low = 0x7fffffff
mask = 0x9908b0df
state = cur
for i in range(623,-1,-1):
tmp = state[i]^^state[(i+397)%624]
# recover Y,tmp = Y
if tmp & high == high:
tmp ^^= mask
tmp <<= 1
tmp |= 1
else:
tmp <<=1
# recover highest bit
res = tmp&high
# recover other 31 bits,when i =0,it just use the method again it so beautiful!!!!
tmp = state[i-1]^^state[(i+396)%624]
# recover Y,tmp = Y
if tmp & high == high:
tmp ^^= mask
tmp <<= 1
tmp |= 1
else:
tmp <<=1
res |= (tmp)&low
state[i] = res
return state

from tqdm import *

statei = states #init
for i in trange(1,150000):
RNG = random.Random()
if((396-i) % 624 == 0):
statei = backtrace_untwist(statei)
statei = [int(i) for i in statei]
RNG.setstate((3,tuple(statei+[624]),None))
else:
statei = [int(i) for i in statei]
RNG.setstate((3,tuple(statei+[(396-i) % 624]),None))
s = [vector(F, [RNG.randrange(0,256) for _ in range(N//2)]) for _ in range(20)]

cipher = AES.new(md5(str(sum(s)).encode()).digest(), AES.MODE_ECB)
enc = "af3010a3de0fa968c38f421f2857d6c60caf9a6ae1023e9d04f253e1d5fb8038fddf26f7cc976fadbb2df12ef549d1fd"
flag = cipher.decrypt(bytes.fromhex(enc))
if(b"n1ctf" in flag):
print(flag)
break


#n1ctf{ISD&LLL_4re_bo7h_v3ry_pow3rfu1_t00ls}

哈哈哈