TryHackMe | Cipher’s Secret Message

One of the Ciphers’ secret messages was recovered from an old system alongside the encryption algorithm, but we are unable to decode it.

Order: Can you help void to decode the message?

Message : a_up4qr_kaiaf0_bujktaz_qm_su4ux_cpbq_ETZ_rhrudm

Dit is de introductie van de room op TryHackMe, die ik opgelost heb. Deze post is mijn eerste “write-up” voor een TryHackMe room. Op Dev.to heb ik deze write-up in het Engels gepubliceerd en die ook ingestuurd naar de maker van de room, ter beoordeling.

Het bericht in de introductie is gecodeerd middels een algoritme, dat eveneens gegeven is in de room:

from secret import FLAG

def enc(plaintext):
    return "".join(
        chr((ord(c) - (base := ord('A') if c.isupper() else ord('a')) + i) % 26 + base) 
        if c.isalpha() else c
        for i, c in enumerate(plaintext)
    )

with open("message.txt", "w") as f:
    f.write(enc(FLAG))

De eerste stap is begrijpen wat deze code doet. In de basis is dat het volgende:
Het algoritme itereert over elk karacter van de te coderen string. Voor elke positie wordt bepaald of dit een letter is (.isalpha() == True) en als dit het geval is, wordt de letter vervangen door middel van verschuiving. Deze verschuiving wordt bepaald door de positie/index van het teken in de string.

Wanneer het teken geen letter is (.isalpha() == False) wordt het teken een op een toegevoegd aan de gecodeerde string.

De tweede stap om deze puzzel op te lossen, was het herschrijven van het algoritme. Zodanig, dat ik zelf de werking ook echt begreep. Weliswaar leverde dat iets meer code op, maar wel code die ik kan uitleggen:

def encode(plaintext):  
    encoded_string = ""  
    replacement_char = ""  
    for i, c in enumerate(plaintext):  
        if c.isalpha():  
            if c.isupper():  
                base=ord('A')  
            else:  
                base=ord('a')  
            replacement_char = chr(((ord(c) - base + i) % 26) + base)  
        else:  
            replacement_char = c  
        encoded_string += replacement_char  
    print(f"Replacement string is {encoded_string}")  
    return encoded_string

Nu ik begrijp wat de code doet, is het natuurlijk tijd om het gecodeerde bericht te decoderen. In feite moet de encode() functie worden omgezet naar een decode() functie en dat doe ik als volgt:

def decode(encoded_text):  
    decoded_string = ""  
    replacement_char = ""  
    for i, c in enumerate(encoded_text):  
        if c.isalpha():  
            if c.isupper():  
                base=ord('A')  
            else:  
                base=ord('a')  
            replacement_char = chr(((ord(c) - base - i) % 26) + base)  
        else:  
            replacement_char = c  
        decoded_string += replacement_char  
    print(f"Replacement string is {decoded_string}")  
    return decoded_string

Heel kort door de bocht is de enige aanpassing die nodig was, het wijzigen van een + naar een -. Door de gecodeerde string als parameter mee te geven aan de decode() functie, wordt de flag van deze room gegeven. Nu enkel nog de waarde in het formaat THM{...} plakken en invoeren op de pagina van deze room en voila:

Congratulations on completing Cipher’s Secret Message!!! 🎉

Wat heb ik geleerd van deze room?

– Het herschrijven van de functie heeft mij geholpen te begrijpen wat er precies gebeurt. Korte code is wellicht goed voor de performance van een applicatie maar niet altijd even goed te begrijpen, zeker als je er niet dagelijks mee bezig bent.
– Het decode-algoritme was verrassend eenvoudig te schrijven, nadat ik eenmaal doorhad hoe het encode-algoritme werkt.

Leave a Reply

Your email address will not be published. Required fields are marked *