方程组求解,题目源码:
from Crypto.Util.number import *
from random import randrange
from grassfield import flag
p = getPrime(16)
k = [randrange(1,p) for i in range(5)]
for i in range(len(flag)):
grasshopper = flag[i]
for j in range(5):
k[j] = grasshopper = grasshopper * k[j] % p
print('Grasshopper#'+str(i).zfill(2)+':'+hex(grasshopper)[2:].zfill(4))
'''
Grasshopper#00:2066
Grasshopper#01:a222
Grasshopper#02:cbb1
Grasshopper#03:dbb4
Grasshopper#04:deb4
Grasshopper#05:b1c5
Grasshopper#06:33a4
Grasshopper#07:c051
Grasshopper#08:3b79
Grasshopper#09:6bf8
Grasshopper#10:2131
Grasshopper#11:2c40
Grasshopper#12:91ba
Grasshopper#13:7b44
Grasshopper#14:5f25
Grasshopper#15:0208
Grasshopper#16:7edb
Grasshopper#17:62b5
Grasshopper#18:cec5
Grasshopper#19:5ab3
Grasshopper#20:3c46
Grasshopper#21:c272
Grasshopper#22:714b
Grasshopper#23:9e0b
Grasshopper#24:48ee
Grasshopper#25:44cc
Grasshopper#26:05a0
Grasshopper#27:3da3
Grasshopper#28:11b1
Grasshopper#29:259f
Grasshopper#30:899d
Grasshopper#31:a130
Grasshopper#32:e58f
Grasshopper#33:23f3
Grasshopper#34:5829
Grasshopper#35:6beb
Grasshopper#36:3681
Grasshopper#37:0054
Grasshopper#38:a189
Grasshopper#39:2765
Grasshopper#40:c63d
Grasshopper#41:bc68
'''
大概的逻辑是p是16bit素数,k是5维向量,元素大小在1到p之间。
flag为长度为42的字符串。flag中每个字符会进行5次处理:
g
r
a
s
s
h
o
p
p
e
r
=
g
r
a
s
s
h
p
p
e
r
.
k
0
.
k
1
.
k
2
.
k
3
.
k
4
grasshopper=grasshpper.k_0.k_1.k_2.k_3.k_4
grasshopper=grasshpper.k0.k1.k2.k3.k4
sage中模拟一下flag前几位的处理过程:
flag = b'flag{'
var('k0 k1 k2 k3 k4')
k = [k0, k1, k2, k3, k4]
res = []
for i in range(len(flag)):
grasshopper = flag[i]
for j in range(5):
k[j] = grasshopper = grasshopper * k[j]
res.append(grasshopper)
print(res)
'''
[102*k0*k1*k2*k3*k4,
1192407267456*k0^5*k1^4*k2^3*k3^2*k4,
1918196473060530916599580974905403195260928*k0^15*k1^10*k2^6*k3^3*k4,
56112321905504104058889432264614118677688107359359075763851172322711550767834986156510191423865157053692191440896*k0^35*k1^20*k2^10*k3^4*k4,
53396244662367707127856864007524389027579357260572582679744127850279999404450619312604004485139827409110793046460181646479623909080635340073160838110289140978788817626824929446784411034165296270303004366240008622426141394072733814130556872463873302593536*k0^70*k1^35*k2^15*k3^5*k4]
'''
实际上每轮k都在变化,可以看出计算过程为:
{
k
11
=
o
r
d
(
′
f
′
)
k
01
,
k
12
=
o
r
d
(
′
f
′
)
k
01
k
02
⋯
k
21
=
o
r
d
(
′
l
′
)
k
11
,
k
22
=
o
r
d
(
′
l
′
)
k
11
k
12
⋯
k
31
=
o
r
d
(
′
a
′
)
k
21
,
k
32
=
o
r
d
(
′
a
′
)
k
21
k
22
⋯
k
41
=
o
r
d
(
′
g
′
)
k
31
,
k
42
=
o
r
d
(
′
g
′
)
k
31
k
32
⋯
k
51
=
o
r
d
(
′
{
′
)
k
41
,
k
52
=
o
r
d
(
′
{
′
)
k
41
k
42
⋯
\left\{ \begin{aligned} k_{11}=ord('f')k_{01},k_{12}=ord('f')k_{01}k_{02} \cdots\\ k_{21}=ord('l')k_{11},k_{22}=ord('l')k_{11}k_{12} \cdots\\ k_{31}=ord('a')k_{21},k_{32}=ord('a')k_{21}k_{22} \cdots\\ k_{41}=ord('g')k_{31},k_{42}=ord('g')k_{31}k_{32} \cdots\\ k_{51}=ord('\{')k_{41},k_{52}=ord('\{')k_{41}k_{42} \cdots\\ \end{aligned} \right.
⎩
⎨
⎧k11=ord(′f′)k01,k12=ord(′f′)k01k02⋯k21=ord(′l′)k11,k22=ord(′l′)k11k12⋯k31=ord(′a′)k21,k32=ord(′a′)k21k22⋯k41=ord(′g′)k31,k42=ord(′g′)k31k32⋯k51=ord(′{′)k41,k52=ord(′{′)k41k42⋯
即
{
o
u
t
1
=
o
r
d
(
′
f
′
)
k
01
k
02
k
03
k
04
k
05
=
k
15
o
u
t
2
=
o
r
d
(
′
l
′
)
k
11
k
12
k
13
k
14
k
15
=
k
25
=
k
24
k
15
o
u
t
3
=
o
r
d
(
′
a
′
)
k
21
k
22
k
23
k
24
k
25
=
k
35
=
k
34
k
25
=
k
33
k
24
k
25
⋯
\left\{ \begin{aligned} out_{1}=ord('f')k_{01}k_{02}k_{03}k_{04}k_{05}=k_{15} \\ out_{2}=ord('l')k_{11}k_{12}k_{13}k_{14}k_{15}=k_{25}=k_{24}k_{15} \\ out_{3}=ord('a')k_{21}k_{22}k_{23}k_{24}k_{25}=k_{35}=k_{34}k_{25}=k_{33}k_{24}k_{25} \\ \cdots\\ \end{aligned} \right.
⎩
⎨
⎧out1=ord(′f′)k01k02k03k04k05=k15out2=ord(′l′)k11k12k13k14k15=k25=k24k15out3=ord(′a′)k21k22k23k24k25=k35=k34k25=k33k24k25⋯
最后推出mod p意义下
k
15
=
o
u
t
1
,
k
25
=
o
u
t
2
,
k
35
=
o
u
t
3
⋯
k
24
=
o
u
t
2
k
15
−
1
,
k
34
=
o
u
t
3
k
25
−
1
,
k
44
=
o
u
t
4
k
15
−
1
⋯
k
33
=
o
u
t
3
(
k
24
k
25
)
−
1
,
k
43
=
o
u
t
4
(
k
34
k
35
)
−
1
,
k
53
=
o
u
t
5
(
k
44
k
45
)
−
1
⋯
k_{15}=out_1,k_{25}=out_2,k_{35}=out_3 \cdots \\ k_{24}=out_2k_{15}^{-1},k_{34}=out_3k_{25}^{-1},k_{44}=out_4k_{15}^{-1} \cdots \\ k_{33}=out_3(k_{24}k_{25})^{-1},k_{43}=out_4(k_{34}k_{35})^{-1},k_{53}=out_5(k_{44}k_{45})^{-1} \cdots
k15=out1,k25=out2,k35=out3⋯k24=out2k15−1,k34=out3k25−1,k44=out4k15−1⋯k33=out3(k24k25)−1,k43=out4(k34k35)−1,k53=out5(k44k45)−1⋯
借鉴了以下这位师傅的解法网鼎青龙组WP
sage exp:
from Crypto.Util.number import *
import gmpy2
out = [0x2066, 0xa222, 0xcbb1, 0xdbb4, 0xdeb4, 0xb1c5, 0x33a4, 0xc051, 0x3b79, 0x6bf8, 0x2131, 0x2c40,0x91ba, 0x7b44, 0x5f25, 0x0208, 0x7edb, 0x62b5, 0xcec5, 0x5ab3, 0x3c46,0xc272, 0x714b, 0x9e0b, 0x48ee, 0x44cc, 0x05a0, 0x3da3, 0x11b1, 0x259f, 0x899d, 0xa130, 0xe58f, 0x23f3, 0x5829, 0x6beb, 0x3681, 0x0054, 0xa189, 0x2765, 0xc63d, 0xbc68]
k = [0]*(50*5)
# Primes in range(max(output),1<<16)
ps = [i for i in range(max(out),1<<16) if isPrime(i)]
for p in ps:
# 循环求解至最后一个字符,判断是否为"}"
flag = 'flag{'
for i in range(0, 42):
k[(i+1)*5+5] = out[i]
for i in range(1, 42):
k[(i+1)*5+4] = out[i] * gmpy2.invert(k[i*5+5], p) % p
for i in range(2, 42):
k[(i+1)*5+3] = out[i] * gmpy2.invert(k[i*5+4]*k[i*5+5], p) % p
for i in range(3, 42):
k[(i+1)*5+2] = out[i] * gmpy2.invert(k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
for i in range(4, 42):
k[(i+1)*5+1] = out[i] * gmpy2.invert(k[i*5+2]* k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
for i in range(5, 42):
x = out[i] * gmpy2.invert(k[i*5+1]*k[i*5+2]* k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
flag = flag + chr(x)
if x == 125:
print(p)
print(flag)
break