ctf
September 1, 2021

WriteUps of WMCTF2021(Crypto)

一次没什么人在打的WMCTF不过题目质量nb,不过我还是只有一个血其他都是第四第五个解出来的qwq…总体是第二个ak crypto的.还行…

checkin

Backpack..
就试试看 二进制下的backpack 然后对应做 发现就其实0b下对应位相差是0和1 相差的话就是相同的值, 就应该是state.然后差不多就传100的时候让你传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
from os import stat
import requests
from bs4 import BeautifulSoup
import random
url = "http://47.104.243.99:10000/show.php"

def getdata(msg):
data = {
"rp": msg
}
r = requests.post(url, data=data)
Soup = BeautifulSoup(r.text, 'lxml')
all_p = Soup.find_all('p')
return (all_p)

flag = int(str(getdata("flag")[1]).split(":")[1].strip('</p>'))
print(flag)#1620418829165478
'''

print(bin(101))
print(bin(102))
print(bin(103))
s = state[2] - state[1]
print(s)
print(state[2] - state[0])
news = []
news.append(state[2] - state[0])
news.append(state[2] - state[1])
print(state[0b1101100-101]-state[0b1101000-101])
print(state[0b1101101-101]-state[0b1101001-101])

'''

flag = int(str(getdata("flag")[1]).split(":")[1].strip('</p>'))
base = 0b10000000000000000000000000000000000000000000000
base_num = (int(str(getdata(base)[1]).split(":")[1].strip('</p>')))
new_state = []
for i in range(32):
tmp = 1<<i
new_state.append(int(str(getdata(base|tmp)[1]).split(":")[1].strip('</p>')) - base_num)
print(new_state)
'''
new_state =[97005071980911, 32652300906411, 73356817713575, 108707065719744, 103728503304990, 49534310783118, 53330718889073, 2121345207564, 46184783396167, 115771983454147, 64261597617025, 2311575715655, 56368973049223, 84737125416797, 24316288533033, 82963866264519, 101019837363048, 25996629336722, 41785472478854, 68598110798404, 40392871001665, 94404798756171, 54290928637774, 112742212150946, 91051110026378, 124542182410773, 40388473698647, 22059564851978, 57353373067776, 80692115733908, 84559172686971, 28186390895657, 97005071980911, 32652300906411, 73356817713575, 108707065719744, 103728503304990, 49534310783118, 53330718889073, 2121345207564, 46184783396167, 115771983454147, 64261597617025, 2311575715655, 56368973049223, 84737125416797, 24316288533033, 82963866264519, 101019837363048, 25996629336722, 0, 68598110798404, 40392871001665, 94404798756171, 54290928637774, 112742212150946, 91051110026378, 124542182410773, 40388473698647, 22059564851978, 57353373067776, 80692115733908, 84559172686971, 125191462876568]
'''
from sage.all import*
nbit = len(new_state)
A = Matrix(ZZ, nbit + 1, nbit + 1)
for i in range(nbit):
A[i, i] = 1
# replace the bottom row with your public key
for i in range(nbit):
A[i, nbit] = new_state[i]
# last element is the encoded message
A[nbit, nbit] = -int(flag)

res = A.LLL()
for i in range(0, nbit + 1):
# print solution
M = res.row(i).list()
nnn = True
for m in M:
if m != 0 and m != 1:
nnn = False
break
if nnn:
print(i, M)
M = ''.join(str(j) for j in M)
M = (int(M[::-1], 2))
print(M)
print(getdata(M))

baby_ocb

构造tag任意解密吧,emmm就拿之前的脚本我发现就可以直接日(
其实就可以直接 看到 是tag和header异或了 ,那么我们可以通过之前的my_pmac计算出来我们的对应的from admin和from baby是啥。
直接异或就可以了

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
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
from pwn import *
from Crypto.Util.number import *
from hashlib import sha256
import string
from pwnlib.util.iters import mbruteforce
import base64
#context.log_level = 'debug'

xor = lambda s1 , s2 : bytes([x1^x2 for x1,x2 in zip(s1,s2)])
table = string.ascii_letters+string.digits

def times2(input_data,blocksize = 16):
assert len(input_data) == blocksize
output = bytearray(blocksize)
carry = input_data[0] >> 7
for i in range(len(input_data) - 1):
output[i] = ((input_data[i] << 1) | (input_data[i + 1] >> 7)) % 256
output[-1] = ((input_data[-1] << 1) ^ (carry * 0x87)) % 256
assert len(output) == blocksize
return output

def times3(input_data):
assert len(input_data) == 16
output = times2(input_data)
output = xor_block(output, input_data)
assert len(output) == 16
return output

def back_times2(output_data,blocksize = 16):
assert len(output_data) == blocksize
input_data = bytearray(blocksize)
carry = output_data[-1] & 1
for i in range(len(output_data) - 1,0,-1):
input_data[i] = (output_data[i] >> 1) | ((output_data[i-1] % 2) << 7)
input_data[0] = (carry << 7) | (output_data[0] >> 1)
# print(carry)
if(carry):
input_data[-1] = ((output_data[-1] ^ (carry * 0x87)) >> 1) | ((output_data[-2] % 2) << 7)
assert len(input_data) == blocksize
return input_data

def xor_block(input1, input2):
assert len(input1) == len(input2)
output = bytearray()
for i in range(len(input1)):
output.append(input1[i] ^ input2[i])
return output

def hex_to_bytes(input):
return bytearray(long_to_bytes(int(input,16)))

def pow():
io.recvuntil(b"XXXX+")
suffix = io.recv(16).decode("utf8")
io.recvuntil(b"== ")
cipher = io.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((x + suffix).encode()).hexdigest() ==
cipher, table, length=4, method='fixed')
io.sendline(proof.encode())

def get_FLAG_data():
io.recv()
io.sendline(b'3')
io.recvuntil(b'ciphertext: ')
ciphertext = base64.b64decode(io.recvline()[:-1])
io.recvuntil(b'tag: ')
tag = base64.b64decode(io.recvline()[:-1])
nonce = b'\x00'*16
associate_data = b'from admin'
return ciphertext,tag,nonce,associate_data

def Server_Enc(msg,nonce):
io.recv()
io.sendline(b'1')
io.recv()
io.sendline(base64.b64encode(nonce))
io.recv()
io.sendline(base64.b64encode(msg))

associate_data = b'from baby'
io.recvuntil(b'ciphertext: ')
ciphertext = base64.b64decode(io.recvline()[:-1])
io.recvuntil(b'tag: ')
tag = base64.b64decode(io.recvline()[:-1])

return ciphertext,tag

def Server_Dec(nonce,cip,tag,associate_data):
io.recv()
io.sendline(b'2')
io.recv()
io.sendline(base64.b64encode(nonce))
io.recv()
io.sendline(base64.b64encode(cip))
io.recv()
io.sendline(base64.b64encode(tag))
io.recv()
io.sendline(base64.b64encode(associate_data))
io.recvuntil(b'plaintext: ')
plaintext = base64.b64decode(io.recvline()[:-1])
return plaintext

def get_my_enc(msg):
nonce = bytearray(os.urandom(16))
fake_m = bytearray(b'\x00'*15+b'\x80'+b'\x00'*16)
cip,tag = Server_Enc(fake_m,nonce)
m0 = bytearray(b'\x00'*15+b'\x80')
m1 = bytearray(b'\x00'*16)

c0 = cip[:16]
c1 = cip[16:]

enc = xor_block(Server_Dec(nonce,xor_block(c0,m0),c1,b""),m0)
A = back_times2(enc)
B = enc
C = xor_block(B,c0)

msg = msg
new_nonce = xor_block(B,m0)
new_msg = xor_block(msg,times2(C)) + m1
new_msg = (bytes(new_msg))
ENC,TAG = Server_Enc(new_msg,new_nonce)

#io.interactive()
return xor_block(ENC[:16],times2(C))

def my_pmac(header, blocksize = 16):
assert len(header)
m = int(max(1, math.ceil(len(header) / float(blocksize))))
offset = get_my_enc(bytearray([0] * blocksize))
offset = times3(offset)
offset = times3(offset)
checksum = bytearray(blocksize)
for i in range(m - 1):
offset = times2(offset)
H_i = header[(i * blocksize):(i * blocksize) + blocksize]
assert len(H_i) == blocksize
xoffset = xor_block(H_i, offset)
encrypted = get_my_enc(xoffset)
checksum = xor_block(checksum, encrypted)
offset = times2(offset)
H_m = header[((m - 1) * blocksize):]
print(H_m)
assert len(H_m) <= blocksize
if len(H_m) == blocksize:
offset = times3(offset)
checksum = xor_block(checksum, H_m)
else:
H_m = H_m + b'\x80'
while len(H_m) < blocksize:
H_m += b'\x00'
assert len(H_m) == blocksize
checksum = xor_block(checksum, H_m)
offset = times3(offset)
offset = times3(offset)
final_xor = xor_block(offset, checksum)
auth = get_my_enc(final_xor)
return auth

if __name__ == "__main__":
io = remote("47.104.243.99",10001)
pow()
F_ciphertext,F_tag,F_nonce,F_associate_data = get_FLAG_data()

print(len(F_ciphertext))
FROMADMIN = my_pmac(b'from admin')
print(FROMADMIN)
FROMBABY = my_pmac(b'from baby')
print(FROMBABY)
F_associate_data = b'from baby'
F_tag = xor_block(xor_block(F_tag, FROMADMIN),FROMBABY)

print(Server_Dec(F_nonce,F_ciphertext,F_tag,F_associate_data))
io.interactive()

ezlsb

next:

get_Prime :

generate:

Airdrop:

Hint:给你n,e,c

Leak:
给你p,e,c 可以尝试让他是实现一个p%4==3 然后去每个按下面这条平方根分解

Backdoor:
就拿到password就可以了。

Main:

4次Airdrop的机会 分解n

r和b是512位素数 sx是368位素数 https://martinralbrecht.wordpress.com/2020/03/21/the-approximate-gcd-problem/
感觉是agcd的加强版

拿一组数据去得到password
对所有的n和gift进行开方之后 发现其实就是上面这个agcd的东西了( lambda 就是384,可以直接拿a
拿到a之后就能用coppper去分解n了
发现后面拿到的p的phi和4096gcd一下只有2,就可以inverse之后再 有限域开平方. 直接是不行的 然后就用p-拿到的值。

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

n = 47935439323457127833037357083983237496878689261127081988649381912739468031720632155196797632254382181519984640185516509133478757768213513987941266551218952702606511178276633908546681835137035411034761316782876147359960487121213984853077540707588650724919247893999205747065241005931759522778403309142776013266993947909627871209547322186129461944966954255478452004126991923307040855781751576009560486080068518925411003611155913186594087392942825850544717133800805624006483035224985413873703244911627183839595554490748948155205230203576672211733145725061218786720271669259766573150046403742640731305478008090581342450251
c = 3919344937892382453030977567508693676032303846339768189327551099374946365060960690768609451174592443590215485748150561581950399880588830921746078740240411900651523182948715415984890388869890625266181130509341855855926592096861408547012789662424413990132921065901887989126066338526922430576216968899218768929718135909294604392991675565238263427980279809833873727879908414057057251514599614783087363407160259495649433827508201133578753184878878951808963235285802411560617758684149245785926009513999665737813112781227632184408328506347530201548662504337685327938279816153782173263392272482010848912768570644687383402740
e = 0x10001
import gmpy2
gift = [n,44990368188010733918858560274483758890181415269493297111432503547349003225605998615045785893226033910128870030617267155471810954946701223520640922021975809987807505611903409246795611631098996240773157768116757200113829094343552868816290020352831816362796203792491207823175523672191727528508633850619433949770456610363882692306556232795718586073455551690290817146381615597057233415356702398751201147360489923331479498200944380380485186742204102241268627281885440725091810845139220728878887230186802227055200861696153582625239928130166788950797548542788617056657074111819043054568673588056230147076007178129781162831611, 78683096763326373669536693596249569085095290247102968419967840631586829732977219369969300751984289814402998022338838702200385790818392667580904195251832143834204909181557079203022588554330880322720341355019524178584242950915453525665150758590809948785874945747350388081180350115247240154475291948408741761648481087095447887536869026145459137082976669264740463624475908502268200243221926503732189641142315206390638626198685135408561463549566690400552904111413732721731304453362155831880117750312809828284867777234323889613356325170410656020466019958496069321445323099847122674429896323552643458809760407340317926830901, 155378045723411522600696035951116955917841229585849918356678240504530602921920566960136486129553454017727749961462685165377347755302826839915112915642536853507763599097574159709699129520153090998679336513853206496584404340204651266745291554668873684828162763771988162464321539837322058407795741726134977433737336303715635638805865795180826546489644742166424956313290523391862752963123672824271036686045932898668866001588000885565313392223064341062105415322004215058987783863547389257154167383707353247208122517429835580960973747381235079792989510459208038145580319784674535377716228024727145018179341727746440515438603, 145996826337300053358889785500361366816465399568166384938579711772423913668332754495063912415488340254571832698805395656780786821255846897561093531075917438583833034671829076937376980928330090827535202591154261056743308762095398623323354628401868490174767786058940272278982366625466222310654778128867887749716594188776848527274133080300896292575037380431855075174589507467705421620952488239054607980417485378752030675364661643727200369011640293898438494036260460375174641137939853447480714174584002881316581265441151705735968822426191526020807499157273552559963397713746419094028547071420597530907758157846952075538021]
G = []
for i in gift:
G.append(gmpy2.iroot(i,2)[0])
from sage.all import *

M = Matrix(ZZ,4+1,4+1)
for i in range(4):
M[i+1,i+1] = -G[0]
for i in range(4):
M[0,i+1] = G[i+1]

M[0,0] = 2** (368)
P=M.LLL()[0]
P0 = (abs(P[0])//M[0,0])
Q = [P0]
#print((bin(P0)))

for i in range(1,5):
tmp = ((P[i]-P0*G[i])//G[0])
Q.append(tmp)
import gmpy2
a = abs(G[0]//Q[0])
print(a)
'''
N = 47935439323457127833037357083983237496878689261127081988649381912739468031720632155196797632254382181519984640185516509133478757768213513987941266551218952702606511178276633908546681835137035411034761316782876147359960487121213984853077540707588650724919247893999205747065241005931759522778403309142776013266993947909627871209547322186129461944966954255478452004126991923307040855781751576009560486080068518925411003611155913186594087392942825850544717133800805624006483035224985413873703244911627183839595554490748948155205230203576672211733145725061218786720271669259766573150046403742640731305478008090581342450251
pbar = 15606058170269190953682935674386408585241503399431015536676436247560293934016890029594865561178385431706188686337043777633715364517948170845087640826845217
ZmodN = Zmod(N)
P.<x> = PolynomialRing(ZmodN)
f = pbar**2 + x
x0 = f.small_roots(X=2^368, beta=0.1,epsilon = 0.01)
p = pbar + x0[0]
print("p: ", p)
243549051613825768264099803511229671296850562269513049496935511304072171908221622373325530141385783545202972578556352456412692718100967837804917914686772005951461971082613057233161910519390099300130916541889963526259281974154202935031489884213351283127857066122909931059096582655197258061167540446985751813009
'''
p = 243549051613825768264099803511229671296850562269513049496935511304072171908221622373325530141385783545202972578556352456412692718100967837804917914686772005951461971082613057233161910519390099300130916541889963526259281974154202935031489884213351283127857066122909931059096582655197258061167540446985751813009
q = 47935439323457127833037357083983237496878689261127081988649381912739468031720632155196797632254382181519984640185516509133478757768213513987941266551218952702606511178276633908546681835137035411034761316782876147359960487121213984853077540707588650724919247893999205747065241005931759522778403309142776013266993947909627871209547322186129461944966954255478452004126991923307040855781751576009560486080068518925411003611155913186594087392942825850544717133800805624006483035224985413873703244911627183839595554490748948155205230203576672211733145725061218786720271669259766573150046403742640731305478008090581342450251//p
phi = (p-1)*(q-1)
d = inverse(0x10001,phi)
print(long_to_bytes(pow(c,d,47935439323457127833037357083983237496878689261127081988649381912739468031720632155196797632254382181519984640185516509133478757768213513987941266551218952702606511178276633908546681835137035411034761316782876147359960487121213984853077540707588650724919247893999205747065241005931759522778403309142776013266993947909627871209547322186129461944966954255478452004126991923307040855781751576009560486080068518925411003611155913186594087392942825850544717133800805624006483035224985413873703244911627183839595554490748948155205230203576672211733145725061218786720271669259766573150046403742640731305478008090581342450251)))

c = 26477776136511814537867182410042935036751631193394882824790793880743251563906439761929648379057880893788211246254847830996292172157860942596330440504204415170090503913269874666809421512135396019520075970999555199447275211351781765139220570319976413703772788491129400862990098026864762589440254742120432827191
n = 462759013310826480654170350879608056333317185952185294792509715751354925534996431275210016348827150025558626490699228055937593844557693779418456113065581193070896452111537933875515496157080452283253231904539734791991415148758529596162008849892665895353050001859515122987866725231231752910748407229540350263791
c1 = pow(c,inverse(4096,n-1),n)
c2 = pow(c1,(n+1)//4,n)
print(long_to_bytes(n-c2))

打交互

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
from pwn import *
from Crypto.Util.number import *
from hashlib import sha256
import string
from pwnlib.util.iters import mbruteforce
#context.log_level = 'debug'

table = string.ascii_letters+string.digits

def passpow():
io.recvuntil(b"XXXX+")
suffix = io.recv(16).decode("utf8")
io.recvuntil(b"== ")
cipher = io.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((x + suffix).encode()).hexdigest() ==
cipher, table, length=4, method='fixed')
io.sendline(proof.encode())

def get_gift():
io.recv()
io.sendline(b'1')
io.recvuntil(b'gift: ')
gift = int(io.recvline()[:-1])
return gift

def get_data():
io.recv()
io.sendline(b'3')
io.recvuntil(b'n = ')
n = int(io.recvline()[:-1])
io.recvuntil(b'e = ')
e = int(io.recvline()[:-1])
io.recvuntil(b'c = ')
c = int(io.recvline()[:-1])
return n,e,c

if __name__ == "__main__":
io = remote("47.104.243.99",9999)
passpow()
n,e,c = get_data()
print(n,c)
gift = []
for i in range(4):
gift.append(get_gift())

#print(gift)

password = b'Cou1d_I_get_Th3_passw03d_then_captu7e_the_fla9?'
io.sendline(b'2')
io.recv()
io.sendline(password)
io.recvuntil(b'n = ')
n = int(io.recvline()[:-1])
e = 4096
io.recvuntil(b'c = ')
c = int(io.recvline()[:-1])
print(c)
print(n)
io.interactive()

ezl1ner

每次传输的值只能是f0的倍数

已经能拿到f0了.
每次左移一格( 然后打过去,发现key我们是可以自己知道的 拿到f0的时候,那么我们只需要去对他进行一次实现,拿个key,之后就是解矩阵方程了

https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E5%AF%86%E7%A0%81/2250150?fr=aladdin

$$
secretKey=C\mod q\
secret=C
Key^-1\mod q
$$

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
from pwn import *
from Crypto.Util.number import *
from hashlib import sha256
import string
from pwnlib.util.iters import mbruteforce

q = 2**24
tat = string.ascii_letters+string.digits

def pass_pow():
io.recvuntil(b"XXXX+")
suffix = io.recv(16).decode("utf8")
io.recvuntil(b"== ")
ciphers = io.recvline().strip().decode("utf8")
print(ciphers)
proof = mbruteforce(lambda x: sha256((x + suffix).encode()).hexdigest() ==
ciphers, tat, length=4, method='fixed')
io.recv()
io.sendline(proof)

def get_init_data():
n = int(io.recvline()[:-1])
e = 0x10001
io.recvuntil(b' only two chances.\n')
c0 = int(io.recvline()[:-1])
return n,e,c0

def give_key(key,num):
for i in range(15):
io.recvuntil(b'key'+num+b':')
io.sendline(str(key[i]).encode())
io.recvuntil(b'here is your cipher:')
cipher = eval(io.recvline()[:-1])
return cipher

def to_vec(num , length):
vec = []
while length > 0:
vec = [num % q] + vec
num //= q
length -= 1
return vec

def vec_to_num(vec):
num = 0
for i in vec:
num = num *q
num = num + i
return num

def to_mat(numlist):
M =[]
for i in numlist:
M.append(to_vec(i , 40))
return M

from sage.all import*
if __name__ == "__main__":
io = remote("47.104.243.99",31923)
#io.interactive()
pass_pow()
#io = remote("192.168.50.123",10006)
n,e,c0 = get_init_data()
#1round

key1 = []
for i in range(15):
c1 = (pow((1<<480) + 1 + (1<<(480+24*i)) , e , n ) * c0 ) % n
key1.append( c1 )

cipher1 = give_key( key1 , b'1')

f0_vec = cipher1[20:]
f0 = vec_to_num(f0_vec)

key1_I_GIVE =to_mat([f0]+[(1<<(480+24*i))*f0 for i in range(15)])
CC = Matrix(Zmod(q),[cipher1])
KK = Matrix(Zmod(q),key1_I_GIVE)
secret = (KK.solve_left(CC))

print(secret)


#2round
cf0 = eval(io.recvline()[:-1])
key2 = []
for i in range(15):
c2 = (pow((1<<480)*2 + 1,e,n)*cf0)%n
key2.append(c2)

cipher2 = give_key(key2,b'2')
cf0_vec = cipher2[20:]
cf0 = vec_to_num(cf0_vec)
key2_I_GIVE =to_mat([(1)*cf0]+[(1<<480)*cf0 for i in range(15)] )
#print(key2_I_GIVE)
#print(cf0)
CC = Matrix(Zmod(q),[cipher2])
KK = Matrix(Zmod(q),key2_I_GIVE)
#print(KK.solve_left(CC))
sss = (secret[0])
s = " ".join(str(i) for i in sss)
print(s)
io.sendline(s)
io.interactive()

About this Post

This post is written by Hao Jiang, licensed under CC BY-NC 4.0.

#ctf#cryptography