Sembra che la prima versione avesse una debolezza, ma di sicuro questa nuova release sarà sicurissima!
La challenge cifra la flag utilizzando una specie di one time pad con numeri casuali.
Le uniche differenze con la versione 1 della challenge sono che è stato tolto il seeding con il timestamp, ma è anche stata tolta la riduzione in modulo. In particolare, la funzione di encryption è
Avendo a disposizione il server remoto che cifra la flag quante volte vogliamo, possiamo condurre un'analisi statistica sui ciphertext restituiti.
L'osservazione fondamentale è che, poiché
In particolare, mandando abbastanza richieste possiamo essere quasi certi di ottenere almeno una volta
Per avere una stima quantitativa, supponiamo di interrogare il server
Dato che questo deve succedere per tutti e
from pwn import remote
class Client:
def __init__(self):
self.r = remote("otp2.challs.olicyber.it", 12306)
self.r.recvlines(4)
def get_encrypted(self):
self.r.sendline("e")
res = self.r.recvline(False).decode()
return list(map(int, res.split("-")))
c = Client()
n = 71
collected = [[] for _ in range(n)]
M = 2000
for _ in range(M):
enc = c.get_encrypted()
for i in range(n):
collected[i].append(enc[i])
flag = ""
for i in range(n):
guess = min(*collected[i])
flag += chr(guess)
print(flag)