nahamCon CTF 2022 Cryptography Writeup

XORROX

题目给出了1, 1 ^ k[0], 1 ^ k[0] ^ k[1] ..., 脚本恢复即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import xor
xorrox = [1, 209, 108, 239, 4, 55, 34, 174, 79, 117, 8, 222, 123, 99, 184, 202, 95, 255, 175, 138, 150, 28, 183, 6, 168, 43, 205, 105, 92, 250, 28, 80, 31, 201, 46, 20, 50, 56]
enc = [26, 188, 220, 228, 144, 1, 36, 185, 214, 11, 25, 178, 145, 47, 237, 70, 244, 149, 98, 20, 46, 187, 207, 136, 154, 231, 131, 193, 84, 148, 212, 126, 126, 226, 211, 10, 20, 119]
key = [124, 208]

for i in range(2, len(xorrox)):
recovered_k = xorrox[i] ^ 1
for j in range(i-1, 0, -1):
recovered_k ^= key[j]
key.append(recovered_k)

print(xor(bytes(enc), bytes(key)))

# flag{21571dd4764a52121d94deea22214402}

Unimod

$a = 1$的仿射密码, 但是utf-8. 直接用已知明文恢复密钥, 别忘了改coding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: UTF-8 -*-
ciphertext = '饇饍饂饈饜餕饆餗餙饅餒餗饂餗餒饃饄餓饆饂餘餓饅餖饇餚餘餒餔餕餕饆餙餕饇餒餒饞飫'

M = 0xFFFD

known_plain='f'

k = (ord(ciphertext[0]) - ord(known_plain)) % M

flag = ''

for i in ciphertext:
flag += chr(ord(i) - k % M)

print(flag)

# flag{4e68d16a61bc2ea72d5f971344e84f11}

Baby RSA Quiz

第一问

1
2
3
4
5
6
7
8
 ---------
| Part 1: |
---------
n = 133396139485237
e = 65537
ct = 84868984310322

What is the plaintext (in integer form)?

factorDB分解$n$即可

第二问

1
2
3
4
5
6
 ---------
| Part 2: |
---------
n = 16239596293977903587558967678259215758478058405440973570306485681621682912965195790725836658982055009734195886450949303945192420180521857951121741198322586576847570641247495642483981410676472586512940704648375359703556939043039914803931827127271235237747624255130610539309385835301644732160367939988628779156879087852737906682771387486647980502599636618673048530321191606998899971378774685919554460476636347269100284983912877405608332448886283346446986980888360987308679686532327035877293383880507733224357891899109334045871690444976822566179401967161153855861176490312346231841235770994033366423749110780762798732463
e = 3
ct = 26480272848384180570411447917437668635135597564435407928130220812155801611065536704781892656033726277516148813916446180796750368332515779970289682282804676030149428215146347671350240386440440048832713595112882403831539777582778645411270433913301224819057222081543727263602678819745693540865806160910293144052079393615890645460901858988883318691997438568705602949652125

$n$太大, $e$太小, gmpy2.iroot 开根即可

第三问

1
2
3
n = 51382952527104538762176174397085320817059137874623719148840442148348202294040187737929065797707451474287116624644099093526180709880089393885605938809569214375736860440338605863242610424220176987295351567911977597565751770045700033317783784024015164845097264555457693270724773814149968428260566283933121285959
e = 65537
ct = 297144177027309977940226855963696434640694560841047172282175432838166587352568339331323424264252998125174813554028457928963853408019254609141170012699867754827701211579981450220386066723558756896023013415795998395660455324295621158859079308999781633660241513861710054002758461709842075798701419354552739269

题目给了提示, $p, q$很接近, 开根后用gmpy2.next_prime找到其中一个因子

MAC and Cheese

题目给出了一个 7-block AES-CBC 签名机 要求验证一个 block 数能被 $8$整除的消息.

不难发现, $7 * 8 = 56$. 签名机的IV为全零比特, 所以将一次签名后的MAC与下一次签名消息的首个block异或后重复$7$次即可.

iv ^ plaintext ^ prev = plaintext ^ prev, 这等价于连续签名.

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
from pwn import *
r = remote('challenge.nahamcon.com', 30285)
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(b'\x00'*16*7)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h1 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'1')
r.sendline(h1 + b'\x00'*16*6)
r.recvuntil(b': ')
h2 = bytes.fromhex(r.recvline().decode())
r.recvuntil(b'? ')
r.sendline(b'2')
r.sendline(b'\x00'*16*8*7 + h2)
r.interactive()

# flag{76a74e3680aea8675a3ae1421a9993eb}

若签名机的IV不为全零比特, 下一次签名消息的首个block要多异或一个$IV$