Cipher's Secret Message

CTF : https://tryhackme.com/room/hfb1cipherssecretmessage

In this beginner-friendly cryptography challenge , we're presented with a scrambled message and its corresponding encryption algorithm.

We're told:

  • A secret message was extracted from an old system.

  • The encryption algorithm is provided (source code).

  • Our job is to reverse the encryption to recover the original message (the flag).

This is a classic example of a custom Caesar cipher variant, where each letter is shifted by its position in the string (index-based shifting). Our goal is to reverse this shifting logic and extract the original plaintext.

πŸ“„ Encrypted Message:

a_up4qr_kaiaf0_bujktaz_qm_su4ux_cpbq_ETZ_rhrudm

Source Code of encryption algorithm:

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))

I tried to simplify the encryption algorithm .Here's the simplified version

plainText = "dummy"
encoded = ""

for i, c in enumerate(plainText):
    if c.isalpha():
        base = ord('A') if c.isupper() else ord('a')
        shifted = (ord(c) - base + i) % 26 + base
        encoded += chr(shifted)
    else:
        encoded += c

print(encoded)

Let's try to understand the algorithm ,so it implements a custom Caesar cipher where each alphabet character in the input string is shifted by its position index in the string. Non-alphabet characters are left unchanged.

What's Happening:

  • enumerate(plainText) gives both the index i and the character c.

  • If the character c is an alphabet letter:

    • Determine the base ASCII code: 'A' for uppercase or 'a' for lowercase.

    • Convert c to its alphabetical index (0–25), add the current index i, and apply modulo 26 to wrap around the alphabet.

    • Convert the result back to a character and append to the encoded string.

  • If the character is not a letter (like digits or symbols), it's added unchanged. Example:

For input: "dummy"

  • 'd' at index 0 β†’ shift by 0 β†’ 'd'

  • 'u' at index 1 β†’ shift by 1 β†’ 'v'

  • 'm' at index 2 β†’ shift by 2 β†’ 'o'

  • 'm' at index 3 β†’ shift by 3 β†’ 'p'

  • 'y' at index 4 β†’ shift by 4 β†’ 'c'

So, output is:

"dvopc"

Now we have simplified the code so it is not difficult for us to reverse engineer this code .

encoded="a_up4qr_kaiaf0_bujktaz_qm_su4ux_cpbq_ETZ_rhrudm"
reversed=""

for i,c in enumerate(encoded):
    if c.isalpha():
        base=ord('A') if c.isupper() else ord('a')
        shifted = (ord(c) - base - i) % 26 + base
        reversed += chr(shifted)
    else:
        reversed += c
    
print(reversed)

Bingo we got our flag

Last updated