0%

2023-CakeCTF-Crypto-WP

CakeCTF Crypto WP

强网拟态看了几眼题,不想打了,去做隔壁的比赛。

Simple_Signature:

题目:

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
import os
import sys
from hashlib import sha512
from Crypto.Util.number import getRandomRange, getStrongPrime, inverse, GCD
import signal


flag = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}")

p = getStrongPrime(512)
g = 2


def keygen():
while True:
x = getRandomRange(2, p-1)
y = getRandomRange(2, p-1)
w = getRandomRange(2, p-1)

v = w * y % (p-1)
if GCD(v, p-1) != 1:
continue
u = (w * x - 1) * inverse(v, p-1) % (p-1)
return (x, y, u), (w, v)


def sign(m, key):
x, y, u = key
r = getRandomRange(2, p-1)

return pow(g, x*m + r*y, p), pow(g, u*m + r, p)


def verify(m, sig, key):
w, v = key
s, t = sig

return pow(g, m, p) == pow(s, w, p) * pow(t, -v, p) % p


def h(m):
return int(sha512(m.encode()).hexdigest(), 16)


if __name__ == '__main__':
magic_word = "cake_does_not_eat_cat"
skey, vkey = keygen()

print(f"p = {p}")
print(f"g = {g}")
print(f"vkey = {vkey}")

signal.alarm(1000)

while True:
choice = input("[S]ign, [V]erify: ").strip()
if choice == "S":
message = input("message: ").strip()
assert message != magic_word

sig = sign(h(message), skey)
print(f"(s, t) = {sig}")

elif choice == "V":
message = input("message: ").strip()
s = int(input("s: ").strip())
t = int(input("t: ").strip())

assert 2 <= s < p
assert 2 <= t < p

if not verify(h(message), (s, t), vkey):
print("invalid signature")
continue

print("verified")
if message == magic_word:
print(f"flag = {flag}")
sys.exit(0)

else:
break

exp:

服务器上面dump数据直接丢进脚本就好了:

1
2
3
4
5
6
7
8
9
10
p = 
vkey =
w,v = vkey[0],vkey[1]

m = "cake_does_not_eat_cat"
s = pow(g,(h(m)-1)*invert(w,p-1),p)
t = pow(g,invert(-v,p-1),p)
print(s)
print(t)
print(verify(h(m),(s,t),vkey))

janken-vs-yoshiking-2

石头剪刀布,要求预测出手。

本质上是个矩阵离散对数问题。

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
# This file was *autogenerated* from the file server.sage
from sage.all_cmdline import * # import sage library

_sage_const_1 = Integer(1); _sage_const_2 = Integer(2); _sage_const_3 = Integer(3); _sage_const_256 = Integer(256); _sage_const_1000 = Integer(1000); _sage_const_1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111 = Integer(1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111); _sage_const_5 = Integer(5); _sage_const_0 = Integer(0); _sage_const_100 = Integer(100)
import random
import signal
import os

HANDNAMES = {
_sage_const_1 : "Rock",
_sage_const_2 : "Scissors",
_sage_const_3 : "Paper"
}

def commit(M, m):
while True:
r = random.randint(_sage_const_2 , _sage_const_2 **_sage_const_256 )
if r % _sage_const_3 + _sage_const_1 == m:
break
return M**r, r


signal.alarm(_sage_const_1000 )

flag = os.environ.get("FLAG", "neko{old_yoshiking_never_die,simply_fade_away}")
p = _sage_const_1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111
M = random_matrix(GF(p), _sage_const_5 )
print("[yoshiking]: Hello! Let's play Janken(RPS)")
print("[yoshiking]: Here is p: {}, and M: {}".format(p, M.list()))

round = _sage_const_0
wins = _sage_const_0
while True:
round += _sage_const_1
print("[system]: ROUND {}".format(round))

yoshiking_hand = random.randint(_sage_const_1 , _sage_const_3 )
C, r = commit(M, yoshiking_hand)
print("[yoshiking]: my commitment is={}".format(C.list()))

hand = input("[system]: your hand(1-3): ")
print("")
try:
hand = int(hand)
if not (_sage_const_1 <= hand <= _sage_const_3 ):
raise ValueError()
except ValueError:
print("[yoshiking]: Ohhhhhhhhhhhhhhhh no! :(")
exit()

print("[yoshiking]: My hand is ... {}".format(HANDNAMES[yoshiking_hand]))
print("[yoshiking]: Your hand is ... {}".format(HANDNAMES[hand]))
result = (yoshiking_hand - hand + _sage_const_3 ) % _sage_const_3
if result == _sage_const_0 :
print("[yoshiking]: Draw, draw, draw!!!")
print("[yoshiking]: I'm only respect to win!")
print("[system]: you can check that yoshiking doesn't cheat")
print("[system]: here's the secret value: {}".format(r))
exit()
elif result == _sage_const_1 :
print("[yoshiking]: Yo! You win!!! Ho!")
wins += _sage_const_1
print("[system]: wins: {}".format(wins))

if wins >= _sage_const_100 :
break
elif result == _sage_const_2 :
print("[yoshiking]: Ahahahaha! I'm the winnnnnnner!!!!")
print("[yoshiking]: You, good loser!")
print("[system]: you can check that yoshiking doesn't cheat")
print("[system]: here's the secret value: {}".format(r))
exit()

print("[yoshiking]: Wow! You are the king of roshambo!")
print("[yoshiking]: suge- flag ageru")
print(flag)

先贴WP:

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
from pwn import *
from sage.all import *
#context(log_level='debug')
p = 1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111

def MakeMatrix(A):
T = []
for i in range(5):
tmp = []
for _ in range(5):
tmp .append(A[_+i*5])
T.append(tmp)
T = matrix(Zmod(p), T)
return T

while True:
io = remote('crypto.2023.cakectf.com',10555)
io.recvuntil(b'and M: ')
M = eval(io.recvuntil(b'\n'))
M = MakeMatrix(M)
print(M)
try:
B,P = M.eigenmatrix_right()
break
except NotImplementedError:
io.close()
continue

P_inv = P.inverse()
print('????????????????????????????????????')

def getC(io):
io.recvuntil(b'commitment is=')
C = eval(io.recvuntil(b']'))
return C

def Calc(B,P,C,P_inv):
B_=((P_inv*C*P)[0])[0]
b=(B[0])[0]
x=discrete_log(mod(B_,p),mod(b,p))
m = x%3+1
result = (m+2) %3
if result == 0:
return 3
else:
return result

for i in range(100):
C = MakeMatrix(getC(io))
#print(f'____C={C}')
my_hand = str(Calc(B,P,C,P_inv)).encode()
io.recvuntil(b'(1-3): ')
io.sendline(my_hand)
io.interactive()
#CakeCTF{though_yoshiking_may_die_janken_will_never_perish}

轰炸东京

dingdong:

task:

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
import os
from base64 import b64decode, b64encode
from hashlib import md5
from datetime import datetime
from Crypto.Cipher import AES

FLAG = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}")
PREFIX = os.environ.get("PREFIX", "cake").encode()

KEY = os.urandom(16)
IV = os.urandom(16)
aes = AES.new(KEY, AES.MODE_ECB)

xor = lambda a, b: bytes([x^y for x, y in zip(a, b)])

def pad(data: bytes):
l = 16 - len(data) % 16
return data + bytes([l]*l)

def unpad(data: bytes):
return data[:-data[-1]]

def encrypt(plain: bytes):
plain = pad(plain)
blocks = [plain[i:i+16] for i in range(0, len(plain), 16)]
ciphers = [IV]
for block in blocks:
block = xor(block, md5(ciphers[-1]).digest())
ciphers.append(aes.encrypt(block))
return b"".join(ciphers)

def decrypt(cipher: bytes):
blocks = [cipher[i:i+16] for i in range(0, len(cipher), 16)]
h = md5(blocks[0]).digest() # IV
plains = []
for block in blocks[1:]:
plains.append(xor(aes.decrypt(block), h))
h = md5(block).digest()
return unpad(b"".join(plains))

def register():
username = b64decode(input("username(base64): ").strip())
if b"root" in username:
print("Cannot register as root user!")
else:
cookie = b"|".join([PREFIX, b"user="+username, str(datetime.now()).encode()])
cookie = encrypt(cookie)
cookie = b64encode(cookie)
print("your cookie =>", cookie.decode())
return

def login():
cookie = input("cookie: ").strip()
cookie = decrypt(b64decode(cookie))
data = cookie.split(b"|")
if (data[0] == PREFIX) and data[1].startswith(b"user="):
username = data[1].split(b"=")[1]
time = data[2]
else:
print("Authentication unsuccessful...")
return
print(f"Hi, {username.decode()}! [registered at {time.decode()}]")
if username != b"root":
print("You're not the root user...")
else:
print("Ding-Dong, Ding-Dong, Welcome, root. The ultimate authority has logged in.")
print("This is for you => ", FLAG)
return

while True:
print("===== MENU =====")
choice = int(input("[1]register [2]login: ").strip())
if choice == 1:
register()
elif choice == 2:
login()
else:
print("Invalid choice")
print()

字节翻转攻击,但是md5

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
from pwn import *

#p = process(['python3', 'server.py'])
p = remote('crypto.2023.cakectf.com', 11111)

want = b'|user=root|date'

def query(query):
p.sendlineafter(b': ', b'1')
p.sendlineafter(b': ', b64e(query).encode())
p.recvuntil(b'=> ')
return b64d(p.recvline())

cipher = query(b'room|date')

IV = cipher[:16]
prefix_enc = cipher[16:32]
first_enc = cipher[32:48]

prefix_hash = md5sum(prefix_enc)
first_hash = md5sum(first_enc)

with log.progress('guess') as prog:
for guess in range(0, 256):
prog.status(f'{guess}')

cur_want = bytes([guess]) + want
block = xor(cur_want, first_hash, prefix_hash)

resp = query(b'room|date' + block)
resp = resp[48:]

p.sendlineafter(b': ', b'2')
p.sendlineafter(b'cookie: ', b64e(IV + prefix_enc + resp).encode())

line = p.recvline().decode()
if 'root' in line:
prog.success()
p.interactive()
break