Sapendo la chiave è facile decifrare. Questa volta sarà più difficile.
Autore: Lorenzo Demeio <@Devrar>
In questa challenge non ci viene più data la chiave per la decifratura, ma abbiamo la possibilità di fare 10 richieste scegliendo un testo cifrato, che verrà decifrato dal server. Fatto ciò, ci viene chiesto di decifrare un testo casuale per 100 volte.
Il nostro obiettivo è recuperare la chiave utilizzando le 10 richieste a disposizione. Chiamiamo
Dalla challenge precedente sappiamo che dallo step i
della cifratura, il carattere in posizione i
del plaintext rimane invariato. Quindi, scegliendo un testo con tutti caratteri distinti, otteniamo dell'informazione su
- Supponiamo di inviare il testo
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX
. - L'output sarà qualcosa del tipo
aNihEPVAwqnMOILXHFcvTUsjdefGJbQpWrDzklSKmuyxtgCRoB
- Siccome dal secondo step in poi il carattere
N
non ha mai cambiato posizione, sappiamo che è arrivato alla seconda posizione al primo step. - Dato che all'inizio era alla posizione 39, sappiamo
$n_a = 11 \mod{49}$ . - Procedendo così otteniamo
$n_N \mod{48}$ ,$n_i \mod{47}$ e così via.
Per ottenere i valori esatti degli
Una volta recuperata la chiave possiamo decifrare usando la soluzione della challenge precedente.
import os
from pwn import remote
import random
import string
import math
from sympy.ntheory.modular import crt
HOST = os.environ.get("HOST", "localhost")
PORT = int(os.environ.get("PORT", 34001))
alph = string.ascii_letters + string.digits
n = 50
def spin(w, n):
n = n % len(w)
return w[-n:] + w[:-n]
def decrypt(ct, key):
pt = ct
for i in range(n-1, 0, -1):
k = key[pt[i-1]]
pt = pt[:i] + spin(pt[i:], -k)
return pt
chall = remote(HOST, PORT)
key = {x: [(0, 1)] for x in alph}
for _ in range(10):
payload = ''.join(random.sample(alph, n))
chall.sendlineafter(b": ", payload.encode())
ans = chall.recvline().decode().split(": ")[1].strip()
tmp = payload
for i in range(n-2):
k = n-i-1 - tmp[i+1:].index(ans[i+1])
key[tmp[i]].append((k, n-i-1))
tmp = tmp[:i+1] + spin(tmp[i+1:], k)
my_key = {x: int(crt([y[1] for y in key[x]], [y[0] for y in key[x]])[0]) % int(math.lcm(*[y[1] for y in key[x]])) for x in alph}
for _ in range(100):
ct = chall.recvline().decode().split(": ")[1].strip()
pt = decrypt(ct, my_key)
chall.sendlineafter(b": ", pt.encode())
print(chall.recvline().decode())