第二届黄河流域网络安全技能挑战赛

Crypto题解

baby_dfa

task.py

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
#!/usr/bin/python3
from random import sample
from os import urandom
from secret import flag
from binascii import unhexlify

logo = '''


.---. ,--, ____
/. ./| ,--.'| ,' , `.
.--'. ' ; | | : ,---. ,-+-,.' _ |
/__./ \ : | : : ' ' ,'\ ,-+-. ; , ||
.--'. ' \' . ,---. | ' | ,---. / / | ,--.'|' | || ,---.
/___/ \ | ' ' / \ ' | | / \ . ; ,. : | | ,', | |, / \
; \ \; : / / | | | : / / ' ' | |: : | | / | |--' / / |
\ ; ` | . ' / | ' : |__ . ' / ' | .; : | : | | , . ' / |
. \ .\ ; ' ; /| | | '.'| ' ; :__ | : | | : | |/ ' ; /|
\ \ ' \ | ' | / | ; : ; ' | '.'| \ \ / | | |`-' ' | / |
: ' |--" | : | | , / | : : `----' | ;/ | : |
\ \ ; \ \ / ---`-' \ \ / '---' \ \ /
'---" `----' `----' `----'
___
,--.'|_
| | :,' ,---.
: : ' : ' ,'\
.;__,' / / / |
| | | . ; ,. :
:__,'| : ' | |: :
' : |__ ' | .; :
| | '.'| | : |
; : ; \ \ /
| , / `----'
---`-' ____
,' , `. ,---, ,---,. ,---,
,-+-,.' _ | .' .' `\ ,' .' | ' .' \
,-+-. ; , || ,--, ,---.' \ ,---.' | / ; '.
,--.'|' | ;| ,'_ /| | | .`\ | | | .' : : \
| | ,', | ': .--. | | : : : | ' | : : : : | /\ \
| | / | | || ,'_ /| : . | | ' ' ; : : | |-, | : ' ;. :
' | : | : |, | ' | | . . ' | ; . | | : ;/| | | ;/ \ \
; . | ; |--' | | ' | | | | | : | ' | | .' ' : | \ \ ,'
| : | | , : | : ; ; | ___ ' : | / ; ' : ' | | ' '--'
| : ' |/ ' : `--' \ .' .`| | | '` ,/ | | | | : :
; | |`-' : , .-./ .' .' : ; : .' | : \ | | ,'
| ;/ `--`----' ,---, ' .' | ,.' | | ,' `--''
'---' ; | .' '---' `----'
`---'
'''

_memu = '''
1. Encrypt
2. Get flag
3. Exit
'''


def rotl(x, n): return ((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff)


def xorl(x, y): return list(map(lambda a, b: a ^ b, x, y))


def i2l(x): return [x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]


def l2i(x): return x[0] << 24 | x[1] << 16 | x[2] << 8 | x[3]


class Enc:
def __init__(self, key: bytes):
self.K = key
self.S = sample([i for i in range(256)], 256)

def l(self, B: list) -> list:
B = l2i(B)
B = B ^ rotl(B, 2) ^ rotl(B, 10) ^ rotl(B, 18) ^ rotl(B, 24)
return i2l(B)

def encrypt(self, plain: bytes) -> bytes:
T = xorl(self.K[:4], plain)
T = self.l([self.S[i] for i in T])
T = xorl(self.K[4:], T)
return bytes(T).hex()


def E():
plain = input("plz enter your plaintext: ")
if len(plain) != 8:
print("wrong length")
exit(0)
print(C.encrypt(unhexlify(plain)))


def get_flag():
print(f"cipher is {f}")
plain = input("plz enter your plaintext: ")
if len(plain) != 8:
print("wrong length")
exit(0)
c = C.encrypt(unhexlify(plain))
if c == f:
print(flag)
exit(0)
else:
print("fake!")
exit(0)


def memu():
choose = input("> ")
if choose == "1":
E()
elif choose == "2":
get_flag()
else:
print("bye!~")
exit(0)


if __name__ == "__main__":
print(logo)
key = urandom(8)
C = Enc(key)
f = C.encrypt(urandom(4))
print(f"sbox: {C.S}")
print(_memu)
while True:
memu()

参考:Crypto趣题-分组密码 | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)

原理没理解清楚,改改exp先跑了个flag,后续找时间重做

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
from Crypto.Util.number import *
from pwn import *
from binascii import *
from z3 import *

def rotl(x, n): return ((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff)

def xorl(x, y): return list(map(lambda a, b: a ^ b, x, y))

def List2Int(x): return x[0] << 24 | x[1] << 16 | x[2] << 8 | x[3]

def Int2List(x): return [x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]

def l(B):
B = List2Int(B)
B = B ^ rotl(B, 2) ^ rotl(B, 10) ^ rotl(B, 18) ^ rotl(B, 24)
return Int2List(B)

def decrypt(K,cipher,inv_S):
T = List2Int(xorl(K[4:],cipher))
s = Solver()
B = BitVec('B',32)
s.add(B ^ rotl(B, 2) ^ rotl(B, 10) ^ rotl(B, 18) ^ rotl(B, 24) == T)
if s.check() == sat: #检测是否有解
result = str(s.model())
T = Int2List(int(result[5:-1]))
for i in range(len(T)):
T[i] = inv_S[T[i]]
T = List2Int(xorl(K[:4],T))
return long_to_bytes(T).hex()

def getflag():
while(1):
try:
r = remote("60.204.206.104",7000)
r.recvuntil(b"sbox: ")
S = eval(r.recvline())
inv_S = [0 for i in range(256)]
for i in range(256):
inv_S[S[i]] = i

x = []
#0
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(b"\x00"*4))
x.append(unhexlify(r.recvline().strip()))

#1
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(b"\x00"*3 + b"\x01"*1 +b"\x00"*0))
x.append(unhexlify(r.recvline().strip()))

#2
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(b"\x00"*2 + b"\x01"*1 +b"\x00"*1))
x.append(unhexlify(r.recvline().strip()))

#3
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(b"\x00"*1 + b"\x01"*1 +b"\x00"*2))
x.append(unhexlify(r.recvline().strip()))

#4
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(b"\x00"*0 + b"\x01"*1 +b"\x00"*3))
x.append(unhexlify(r.recvline().strip()))


#获取key
key_prefix = []

#1.获取key[:4]
for i in range(1,5):
if(i % 2 == 0):
temp = (xorl(x[0],x[i]))[i-2]
elif(i % 2 == 1):
temp = (xorl(x[0],x[i]))[i]
for j in range(255):
t1 = (S[j]>>6) + ((S[j]&0b111111)<<2)
t2 = (S[j^1]>>6) + ((S[j^1]&0b111111)<<2)
if(t1^t2 == temp):
key_prefix.append(inv_S[S[j]])
break
key_prefix = key_prefix[::-1]

#2.获取key[4:]
temp = r.recvuntil(b"> ")
r.sendline(b"1")
temp = r.recvuntil(b"plz enter your plaintext:")
r.sendline(hexlify(long_to_bytes(List2Int(key_prefix))))

key_suffix = Int2List(bytes_to_long(unhexlify(r.recvline().strip())))
T = [0,0,0,0]
temp = l([S[i] for i in T])
key_suffix = xorl(temp, key_suffix)
key_final = long_to_bytes(List2Int(key_prefix)) + long_to_bytes(List2Int(key_suffix))


#获取flag
temp = r.recvuntil(b"> ")
r.sendline(b"2")
temp = r.recvuntil(b"cipher is ")
cipher = unhexlify(r.recvline().strip())
t = decrypt(key_final,cipher,inv_S)
r.sendline(t.encode())
temp = r.recvline()
print(temp)
if(b"fake!" not in temp):
return

r.close()
except:
pass

getflag()
# flag{21a7369e-b123-05cb-e80a-982a4f85308a}

ez_encrypt

task.py

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
from Crypto.Util.number import *
from secret import flag
def f(word, key):
out = ""
for i in range(len(word)):
out += chr(ord(word[i]) ^ key)
return out
m, n = 17, 18
num = [0]*18
flag1,flag2=flag[0:len(flag)//2], flag[len(flag)//2:]
def encrypt_1(key):
L, R = key[0:len(key)//2], key[len(key)//2:]
x=''
for i in range(len(L)):
x += chr(ord(f(R, m)[i]) ^ ord(L[i]))
y = f(R, 2)
L, R = y, x
x=''
for i in range(len(L)):
x += "".join(chr(ord(f(R, n)[i]) ^ ord(L[i])) )
y = f(R, 2)
cipher = x + y
return(cipher)
c1=encrypt_1(flag1)
with open("cipher.txt", "w") as ct:
ct.write(c1 + "\n")
ct.close()
def encrypt_2(key):
l=len(key)
k = 0
for i in range(l):
num[i] = (ord(key[i]) + i) ^ (k % 3 + 1)
num[l-i-1] = ((ord(key[l-i-1]) + l) - i - 1) ^ (k % 3 +1)
k+=1
return num
c2=encrypt_2(flag2)
print("c2=",c2)
#c2= [119, 107, 102, 97, 58, 114, 122, 124, 108, 122, 72, 45, 49, 48, 44, 49, 51, 141]

flag1

记L,R分别为flag1的左半部分和右半部分,由第一部分加密可以知道

x0 = R ^ 17 ^ Ly0 = R ^ 2

x1 = R ^ 17 ^ L ^ 18 ^ R ^ 2y1 = R ^ 17 ^ L ^ 2

x1 = L ^ 17 ^ 18 ^ 2根据x1,很容易推出L = x1 ^ 17 ^ 18 ^ 2

根据y1很容易推出L = y1 ^ 2 ^ 17 ^ R

这里的x1,y1就是cipher的左半部分和右半部分

flag2

第二部分就是把明文先加上索引,再异或上k % 3 + 1

很容易就写出exp

exp.py

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
c2 = [119, 107, 102, 97, 58, 114, 122, 124, 108, 122, 72, 45, 49, 48, 44, 49, 51, 141]

tmp = open("cipher.txt",'rb').read().strip()

c1 = [tmp[i] for i in range(len(tmp))]

left = c1[:len(c1)//2]
right = c1[len(c1)//2:]

def decrypt_2(c):
m = [0 for _ in range(18)]
l = 18
k = 0
for i in range(l):
m[i] = (c[i] ^ (k % 3 + 1)) - i
m[l-i-1] = (c[l-i-1] ^ (k % 3 + 1)) - (l-i-1)
k += 1
key = ""
for i in m:
key += chr(i)

return key

flag2 = decrypt_2(c2)

l = [left[i] ^ 17 ^ 18 ^ 2 for i in range(len(left))]
r = [(right[i] ^ 2) ^ l[i] ^ 17 for i in range(len(left))]

flag1 = ""
for i in range(len(l)):
flag1 += chr(l[i])

for i in range(len(r)):
flag1 += chr(r[i])

print(flag1+flag2)

ez_ntru

task.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from secret import flag
import libnum

bits = 2048
while True:
q = random_prime(2^bits, lbound=2^(bits - 1))
f = random_prime(2^(3*bits//4 - 1))
g = random_prime(2^(bits//4 - 1))
if gcd(f, q*g) == 1:
h = f.inverse_mod(q) * g % q
break
r = random_prime(2^(3*bits//4 - 1))
m = libnum.s2n(flag)
assert m < 2^(bits//4)
c = (r * h + m) % q

print('q = %d' % q)
print('h = %d' % h)
print('c = %d' % c)
q = 24445829856673933058683889356407393860808522483552243481673407476395441107312130500945533047834993780864465577896968035259377721441466959027298166974554621753030728893320770628116412892838297326949997096948374940319126319050202262831370086992122741039059235809755486170276098658609363789670834482459758766315965501103856358827004129316458293962968758091319313119139703281758409686502729987426264868783862562150543872477975124482520151991822540312287812454562890993596447391870392038170902308036014733295394468384998808411243690466996284064331048659179342050962003962851315539367769981491650514319735943099663094899893
h = 4913183942329791657370364901346185016154546804260113829799181697126245901054001842015324265348151984020885129647620152505641164596983663274947698263948774663097557712000980632171097748594337673511102227336174939704483645747401790373320060474777199502879236509921155985395351647045776678540066383822814858118010995298071799515355111562392871675582742450331679030377003011729873888234401630551097244308473512890467393558048369156638425711104036276296581364374424105121033213701940135560177615395895359023414249846471332180098181632276243857635719541258706892559869642925945927703702696983949003370155033272664851406633
c = 23952867341969786229998420209594360249658731959635047659110331734424497403162506614140213749790708068086973241468969253395309243550869149482017583754015801740198734485871141965939993554966887039832701333623276590311516052334557237678750680087492306461195312290860900992532859827406262394480605001436094705579158919540851727801502678160085863180222123880690741582667929660533985778430252783414931317574267109741748071838599712027351385462245528001743693258053631099442571041984251010436099847588345982312217135023484895981833846397834589554744611429133085987275209019352039744743479972391909531680560125335638705509351

由题目可知

$$
h \equiv f^{-1}g \mod q
$$

$$
\therefore g = fh + kq
$$

$q = 2048bit$,$f = 1536bit$,$g = 512bit$

根据数量级,构造格即可求得f,g

又因为
$$
c \equiv rf^{-1}g + m \mod q
$$

$$
\therefore fc \equiv rg + mf \mod q
$$

因为上面求出了f,g,此时把式子模掉$g$,有
$$
fc \equiv (mf \mod q )\mod g
$$

$$
\therefore m \equiv (fc \mod q )\times f^{-1}\mod g
$$

这里的$f^{-1}$是模g的逆元

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import gmpy2
from Crypto.Util.number import *

q = 24445829856673933058683889356407393860808522483552243481673407476395441107312130500945533047834993780864465577896968035259377721441466959027298166974554621753030728893320770628116412892838297326949997096948374940319126319050202262831370086992122741039059235809755486170276098658609363789670834482459758766315965501103856358827004129316458293962968758091319313119139703281758409686502729987426264868783862562150543872477975124482520151991822540312287812454562890993596447391870392038170902308036014733295394468384998808411243690466996284064331048659179342050962003962851315539367769981491650514319735943099663094899893
h = 4913183942329791657370364901346185016154546804260113829799181697126245901054001842015324265348151984020885129647620152505641164596983663274947698263948774663097557712000980632171097748594337673511102227336174939704483645747401790373320060474777199502879236509921155985395351647045776678540066383822814858118010995298071799515355111562392871675582742450331679030377003011729873888234401630551097244308473512890467393558048369156638425711104036276296581364374424105121033213701940135560177615395895359023414249846471332180098181632276243857635719541258706892559869642925945927703702696983949003370155033272664851406633
c = 23952867341969786229998420209594360249658731959635047659110331734424497403162506614140213749790708068086973241468969253395309243550869149482017583754015801740198734485871141965939993554966887039832701333623276590311516052334557237678750680087492306461195312290860900992532859827406262394480605001436094705579158919540851727801502678160085863180222123880690741582667929660533985778430252783414931317574267109741748071838599712027351385462245528001743693258053631099442571041984251010436099847588345982312217135023484895981833846397834589554744611429133085987275209019352039744743479972391909531680560125335638705509351

T = 2^1024
M = Matrix(ZZ,[[1,T*h],[0,T*q]])

f = M.LLL()[0][0]
g = M.LLL()[0][1] // T

tmp = f*c % q
m = tmp * gmpy2.invert(f,g) % g
print(long_to_bytes(int(m)))

baby_math

task.py

1
2
print(sin(__import__('libnum').s2n(flag)).n(1024))
#-0.5763216138185318403737346358040179184476364123728865572799211128243702354488581188939012847259223762780574285919778334891033655170438095281317540535577851035632940469300832811280408518388896020483094512571194149462558073200869265861278472233179527377781153969581392345206909655605217731481771369571884721388

tmp = -0.57............
$$
\because tmp = sin(m)
$$

$$
\therefore m = arcsin(tmp) + 2k\pi
$$

构造格

一般flag长度在40左右,所以$m \approx 320bit$,调整一下参数,构造出

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Util.number import long_to_bytes

tmp = -0.5763216138185318403737346358040179184476364123728865572799211128243702354488581188939012847259223762780574285919778334891033655170438095281317540535577851035632940469300832811280408518388896020483094512571194149462558073200869265861278472233179527377781153969581392345206909655605217731481771369571884721388

asin = arcsin(tmp)
RR = RealField(1024)
pi = RR(pi)


Ge = Matrix(QQ,[[1,0,2^690],[0,2^320,2^690*asin],[0,0,2^690*2*pi]])
m = abs(Ge.LLL()[0][0])
print(long_to_bytes(int(m)))
# flag{b0a8c4f1-c343-40f7-86f8-4f3b9a5cc249}
-------------已经到底啦!-------------