Ez most egy kriptográfiai kihívás volt. Kriptográfiában nem vagyok jártas, de ezt a feladatot meg tudtam csinálni. Először kapunk egy forráskódot. Ez egy szerver, ami az egyik változójában tartalmaz egy flag-et (a forráskód nem tartalmazza az éles szerver flag-jét, azt majd nekünk kell kitalálni), előállít egy véletlen sztringet, XOR-al titkosítja a flag-et, majd kiírja a titkosított üzenetet.
Ezután megkérdezi, hogy mi volt a titkosítási kulcs. Ha eltaláljuk, kapunk egy második flag-et is. A szervert el is indíthatjuk, ami minden indításnál kiírja a titkosított üzenetet, majd kéri a kulcsot. Ha rosszat adunk meg, kilép.
Tehát első látásra lehetetlen a feladat, mert nem ismerjük sem a kulcsot, sem a nyers szöveget, csak a titkosított üzenetet. Nyers erővel sem törhetünk, mert csak egy lehetőségünk van, hogy a választ beírjuk. Kénytelenek leszünk gondolkodni.
Az XOR titkosításnak van egy érdekes tulajdonsága. Ha a titkosított szöveget ismét titkosítjuk ugyan azzal a kulccsal, akkor visszakapjuk a nyers szöveget. Ha viszont a titkosított szöveget az eredeti, nyers üzenettel titkosítjuk újra, akkor pedig a kulcsot kapjuk meg.
Milyen jó lenne ismerni az eredeti üzenetet! Igaz, az eredeti üzenetet nem ismerjük, de bizonyos tulajdonságairól van némi információnk. Például mindig "THM{"-el kezdődik. A forráskódból még az is tudjuk, hogy a kulcs 5 karakter hosszú.
Úgyhogy írtam egy programot, ami végigpróbálta milyen karakter állhat a "THM{" után. Titkosítottam vele a titkosított üzenetet, ezzel kaptam egy lehetséges kulcsot. A kulccsal ismét titkosítottam a titkosított üzenetet és reménykedtem, hogy felismerem majd, melyik lehet a jó megoldás (ugyanis a legtöbb flag nem random, hanem valami üzenet hacker stílusban). Íme a kód:
import string
def decode(hexinput, key):
strinput = bytes.fromhex(hexinput).decode()
xored = ""
for i in range(0, len(strinput)):
xored += chr(ord(strinput[i]) ^ ord(key[i%len(key)]))
return xored
def doit():
hex_encoded = input().strip()
print("This XOR encoded text has flag 1: " + hex_encoded + "\n")
for i in string.ascii_letters + string.digits:
test = decode(hex_encoded, "THM{" + i)[0:5]
out = decode(hex_encoded, test)
if out[-1] == '}':
print("Here is the result with the test", test, out)
doit()
Ahogy böngésztem az eredményeket, feltűnt valami. A jó megoldásnak az üzenet végét "}"-el kell lezárnia. Úgyhogy azt is beleírtam a programba, mint ellenőrzést. Elindítottam a szervert, ami kiírta a titkosított üzenetet. Azt kimásoltam, betettem a programomba, ami kiírta a kulcsot és az első flag-et. A kulcsot visszaírtam a szervernek, mire jutalmul megkaptam a második flag-et is.
Átnéztem, mások hogyan oldották meg, és akinek matematikus vénája van, az hamar rájött, hogy a titkos kulcs ötödik eleme mindig a záró kapcsos zárójelet fogja kódolni, mert a flag hossza 5 többszöröse. Tehát mindig csak egy jó megoldás lehet. Ez nekem nem esett le, de CTF-nek nagyon jó volt.