NPST 15. Bitråte: defeating bit rot

Task description

Brukerveiledningen til en av de eldste maskinene på verkstedet har blitt borte. Heldigvis har Julenissens arkiv 1000 sikkerhetskopier av dokumentet på magnetbånd. Det viser seg at alle kopiene er kraftig angrepet av bit-råte så dokumentet må gjenoppbygges. Ifølge arkivalven så er brukerveiledningen skrevet på gammel-nordpolarsk som har samme alfabet som norsk, men inneholder ikke nye tegn som disse: {}#$[]§¤@

Når du finner ut av det så send meg MD5-sjekksummen til det gjenoppbyggede dokumentet på formen PST{checksum}. Svaret er ikke versalfølsomt.

- Mellomleder

backups.zip

Notes

My first thought is to go through a document, character by character. If a character is in this list {}#$[]§¤@, it should be replaced with the character in another copy.

Solution

After thinking some more it makes more sense to loop through all documents and mapping the most common characters at a given index. Like so:

Document 1:
abcdefghijklmnop

Document 2:
acbdefhgijkpmnol

Document 3:
dbcaefghjiklmnop

Result:
abcdefghijklmnop

Another thing to think about is that the document we’re trying to recover doesn’t contain characters such as {}#$[]§¤@, so in the script I created I chose to get the next most common character at the same index.

solve.py:

import os
import hashlib

document_length = 3271
unknown_letters = list("{}#$[]§¤@")
most_common = b""

for character_idx in range(document_length):
    common_characters = {}

    for document_idx in range(0, 1000):
        character = open(f"backups/manual.bak.{document_idx:03}", "rb").read()[character_idx]
        if character in common_characters:
            common_characters[character] += 1
        else:
            common_characters[character] = 1

    common_characters_sorted = dict(sorted(common_characters.items(), key=lambda item: item[1]))
    offset = 0
    most_common_letter = [*common_characters_sorted.keys()][-1]

    while chr(most_common_letter) in unknown_letters:
        offset += 1
        most_common_letter = [*common_characters_sorted.keys()][-1 - offset]

    most_common += bytes(chr(most_common_letter), "utf-8")

recovered = most_common.decode("utf-8")
print(recovered)

md5sum = hashlib.md5(recovered.encode("iso-8859-1")).hexdigest()
print(f"Flag: PST{{{md5sum}}}")

Output:

Nordpolen Leketo Skapar Maskin Notendahandbok
Innihald

    Inngangur
    Øryggidiltakan
    Maskínuskyring
    Adalnotkun
    Vidhald og Vandrædaleysingar

1. Inngangur

Velkominn a verkstædi Olafs å Nordurpolinu! Dessi notendahandbok leidir dig i gegnum notkun å vårri gagnryni leikja-skapar maskinar. Dessi maskin er hønnud til ad hjålpa Olafi og hans alfum ad skapa leiki sem skulu færa gledi til barna um allan heim. Lesid dessa handbok varsamlega til ad tryggja ørugga og hagkvæma notkun.
2. Øryggisreglur

Øryggi ditt er okkar helsta markmid å verkstædi Olafs. Vinsamlegast fylgdu eftir eftirfarandi øryggisreglum:

    Ekki snertu hreyfanlegar hluta: Halda hendurnar og føtun dinar i burtu frå hreyfanlegum dåttum maskinunnar til ad koma i veg fyrir slikarhåttar åverkanir.
    Eftirlit: Adeins djålfud ålfar hafa heimild til ad vinna vid maskinuna.
    Nota videigandi flikur: Ålfar ættu ad nota vidbuna vørnartæki, dar å medal gleraugu og vettlinga.
    Neysluønn: Kynntu der stadsetningu neysluønnar og hvernig henni er styrt.

3. Maskinuskyring

Leikja-skapar maskinan å verkstædi Olafs er flokin tæki. Her er yfirlit yfir helstu dåttum hennar:

    Flutningabelti: Flytja hråefni og samsett leiki å milli mismunandi verkfæra.
    Leikjasamsettari: Dar breytast hråefnin i leiki.
    Gædaeftirlitstød: Ålfar skoda leikina eftir galla og gæta dess ad deir uppfylli krøfur Olafs.
    Gjafapakkadarstød: Degar leikirnar hafa farid i gegnum gædaeftirlitid, verda dær pakkadar inn i skrautlegan pappir og undirbunar fyrir afhendingu.

4. Adalnotkun

Fylgdu dessum skrefum til ad nota leikja-skapar maskinina:

Skref 1: Upphaf

    Athugadu ad allar øryggisreglur seu fylgdar.
    Slådu å maskinuna med adalhnappinum.
    Fylgdu med stjorntøflunni eftir møøgulegum villuskilabodum.

Skref 2: Hlada inn hråefnum

    Hlada hråefnum å flutningabeltid.
    Tryggja ad hråefnin seu jøfnlega dreifd til ad få jøfn leikjaaframleidslu.

Skref 3: Samsetning leikja

    Maskinan mun sjålfkrafa byrja samsetningu leikjanna.
    Hlyja samsetningarferlid eftir møøgulegum stoppum eda oregluleikum.
    Nota neysluønnina ef naudsyn ber.

Skref 4: Gædaeftirlit

    Skodadu leikina vid gædaeftirlitsstødina.
    Fjarlægja leiki med galla og setja då i tiltekna kistu.
    Yta å "Samdykkt" hnappinn fyrir leiki sem uppfylla krøfur Olafs.

Skref 5: Gjafapøkkun

    Leikir sem komast fram hjå gædaeftirlitinu verda fluttir å gjafapakkadarstødina.
    Tryggja rett pøkkun og merkingu hvers leiks.
    Setja pakkanadu leikina å serstakt flutningabelt fyrir dreifingu.

Skref 6: Lokun

    Degar vinnan er lokid, sløkkva å maskinunni med adalhnappinum.
    Hreinsa burt ohreinindi frå flutningabeltinu og verkfærunum.

5. Vidhald og Vandrædaleysing

Reglulegt vidhald er naudsynlegt til ad halda leikja-skapar maskinina i bestu åstandi. Skodadu vidhaldsåætlanina sem Olafs Verkstædi bydur upp å.

Vandrædaleysing:

Ef du hittir å vandamål vid maskinuna, skodadu vandamålaleysinguna sem gefin er i serskildri vandamålaleggi sem fylgir.

Takk fyrir ad nota leikja-skapar maskina å Nordurpolinu! Vid vonumst til ad dessi handbok hjålpi der ad nota maskinuna å skilvirkan og øruggan hått.

If we calculate the md5 hash of the output above (utf-8) we get the flag.

Flag: PST{e32ba07d1254bafd1683b109c0fd6d6c}