07CTF

Beta Bet – Cryptography Challenge Writeup | 07CTF

oneliner:

AI can definitely solve this problem with ease. The name of this cipher is the Mod-26 additive cipher

Understanding the challange:

  1. If you look at the challange.py file, which is the encoder for this challenge, you will notice a simple encryption method where (plainletter + keyletter) % 26 + ord('a') is used.

  2. The key alphabet contains letters 'b' to 'z', which means it uses 25 letters in total. English contains 26 letters, so already something is suspicious.

  3. Mod 26 always gives you a number between 0 and 25;

Analyzing:

  1. The flag format is: first 6 fixed letters + encrypt(47 letters) + last fixed letter

  2. The key contains only 25 letters. Ignore the randomness for a moment. Even in the worst possible case, assume all letters 'b' to 'z' are used as key options. This means one letter from 'a' to 'z' will always be missing, because the key never allows producing all 26 possible cipher letters. So no matter how many times we encrypt, one ciphertext letter will always be missing.

  3. ord() simply gives the ASCII representation of a character. 'a' = 97, 'b' = 98, 'c' = 99, and so on — they are sequential.

  4. plainletter 'a' + key 'b' => 97 + 98 = 195 195 % 26 = 13 13 + ord('a') = 110 → 'n' So for plaintext 'a', the starting ciphertext letter is 'n'.

  5. Since the key alphabet contains only 25 letters, the maximum possible shift is +25. The alphabet has 26 letters, so the cipher cannot complete the full cycle. That means for each plaintext letter, one ciphertext letter is impossible to generate, which leads to a guaranteed missing letter.

Boring Theory (obviously mine):

  1. The flag's first plaintext letter is 'i'. As we analyzed, if 'i' is used as a plaintext letter, the cipher will generate all alphabet letters except one. When we looked at out.txt, we found that after 113 ciphertexts, the first cipher letter never contained 'u'.

  2. Let’s reverse-engineer this. ASCII value of 'u' = 117. We want to find the plaintext letter that never reaches 'u'. For example, plaintext 'a' starts encrypting at 'n', and its highest possible letter is 'l'. That means 'a' cannot reach 'm'. Its "fuel" runs out before getting there.

  3. So we need to find a letter whose maximum reachable cipherletter is 't' (ASCII 116), which is one less than 'u'. In other words, this plaintext letter's maximum will stop at 't'.

  4. Now compute: ASCII 't' = 116. Then 116 - 97 = 19. Remember this number; it is important for the modulo pattern.

  5. Consider plaintext 'a' and key 'z'. Key 'z' gives the highest possible shift ("highest fuel"). So mathematically: 97 + 122 = 219. Now 219 mod 26 = 11. This reveals the modulo pattern:

    • plainletter 'a' gives 11
    • plainletter 'b' gives 12
    • plainletter 'c' gives 13
    • … and so on.
  1. Now standardize the equation "(ord(P) + ord(K)) % 26". For plaintext 'a', we get 11. For plaintext 'b', we get 12. This continues linearly. So plaintext 'i' will give 19, because 'i' is 8 steps after 'a', and 11 + 8 = 19. That means 'i' can reach cipherletter 't', but can never reach cipherletter 'u'.
  1. Finally, as we discovered, the solving process is: find the cipherletter that never appears in a column across the 113 ciphertexts. Then determine the plaintext letter whose maximum reachable cipherletter stops exactly before that missing letter. This gives you the plaintext letter for that position.

Formula: Find the "never appear" alphabet from the 113 cipher values (check column-wise). Then calculate the letter which cannot generate that missing letter. As such, you will have your full plaintext.

offset = ord(neverappear) - ord('a') - 1 plainletter = chr(86 + offset)

0 people love this