diff --git a/2024/NC3 Jule CTF 2024/PostNordpolen I/README.md b/2024/NC3 Jule CTF 2024/PostNordpolen I/README.md new file mode 100644 index 0000000..992afb9 --- /dev/null +++ b/2024/NC3 Jule CTF 2024/PostNordpolen I/README.md @@ -0,0 +1,24 @@ +# PostNordpolen I + +Et krypto-system hvor AES-CTR mode bruges. + +## Solve + +Efter et antal krypteringer vil `CODEBOOK.next()` løbe tør og gamle værdier genbruges - altså nonce reuse! + +### AES-CTR + +I CounterMode benytter man `AES(key, Nonce||Counter++)` til at skabe et pseudorandom stream af bytes, kaldet et _keystream_ ("ks"). +Så længe man holder _key_ hemmelig, vil _ks_ kunne bruges som et one-time pad og data krypteres ved at XOR'es med KS. + +Hvis _nonce_ ("number used only once") genbruges under samme nøgle, så vil to beskeder blive krypteret med samme keystream, hvilket vil sige hvis man XOR de to ciphertekst sammen får man: + +`CT1 ⊕ CT2 => (MSG1 ⊕ KS) ⊕ (MSG2 ⊕ KS) => MSG1 ⊕ MSG2 ⊕ (KS ⊕ KS) => MSG1 ⊕ MSG2 ⊕ \x00 => MSG1 ⊕ MSG2` + +Altså de to _KS_ går ud med hinanden og hvis man kender MSG1, kan mange regne MSG2 ud. + +Vi benytter dette til at modtage det krypterede flag og derefter kryptere et stort antal beskeder indeholdende "AAA…", når nonce genbruges vil `FLAG_ENC ⊕ ENC(AAA…) ⊕ AAA…` indeholde det dekrypterede flag. + +## Flag + +Se [solve.py](solve.py) diff --git a/2024/NC3 Jule CTF 2024/PostNordpolen I/solve.py b/2024/NC3 Jule CTF 2024/PostNordpolen I/solve.py index 8f90a86..35b1d02 100644 --- a/2024/NC3 Jule CTF 2024/PostNordpolen I/solve.py +++ b/2024/NC3 Jule CTF 2024/PostNordpolen I/solve.py @@ -1,5 +1,8 @@ from pwn import * +def xor(a, b): + return bytes([x ^ y for x, y in zip(a, b)]) + r = remote('10.10.106.188', 1337) r.readuntil(b"> ") r.sendline(b"1") diff --git a/2024/NC3 Jule CTF 2024/PostNordpolen II/solve.py b/2024/NC3 Jule CTF 2024/PostNordpolen II/solve.py new file mode 100644 index 0000000..ce212e6 --- /dev/null +++ b/2024/NC3 Jule CTF 2024/PostNordpolen II/solve.py @@ -0,0 +1,62 @@ +from pwn import * + +def xor(a, b): + return bytes([x ^ y for x, y in zip(a, b)]) + +r = remote('10.10.164.170', 1337) +r.readuntil(b"> ") + +letter = 1 +while letter <= 1000: + if letter % 64 == 0: print(f"{letter=}") + r.sendline(b"1") + r.readuntil(b'\nDu har 1 brev klar til udlevering: ') + ENC_FLAG = bytes.fromhex(r.readuntil(b'\n')[:-1].decode()) + r.readuntil(b"> ") + letter += 1 + +print(f"{letter=}") + +ct0 = ENC_FLAG[0:16] +ct1 = ENC_FLAG[16:32] +ct2 = ENC_FLAG[32:48] +ct3 = ENC_FLAG[48:64] +ct4 = ENC_FLAG[64:80] + +def ENC(msg: bytes) -> bytes: + """ returns result of ENC(key, msg) """ + global letter + r.sendline(b"2") + r.readuntil(b"Besked: ") + r.sendline(b'AAAA') + r.readuntil(b"Adresse: ") + r.sendline(b"") + r.readuntil(b"IV: ") + + assert len(msg) == 16, msg + r.sendline(msg.hex().encode()) + + r.readuntil(b"afsendt til : ") + CRIB = f"[BREV {letter}] AAAA".encode() + result = xor(CRIB, bytes.fromhex(r.readuntil(b'\n')[:-1].decode())) + + r.readuntil(b"> ") + letter += 1 + return result + + +ks0 = xor(ct0, b'[BREV 1000] NC3{') + +ks1 = ENC(ks0) +pt1 = xor(ct1, ks1) + +ks2 = ENC(ks1) +pt2 = xor(ct2, ks2) + +ks3 = ENC(ks2) +pt3 = xor(ct3, ks3) + +ks4 = ENC(ks3) +pt4 = xor(ct4, ks4) + +print(b'NC3{' + pt1 + pt2 + pt3 + pt4)