weirdSnake

Published: April 3, 2024

Description

I have a friend that enjoys coding and he hasn't stopped talking about a snake recently He left this file on my computer and dares me to uncover a secret phrase from it. Can you assist?

Bytecode reversing

Download the bytecode file snake and examine it with tools like uncompyle6 or Python's dis module.

Translate the extracted logic into a new Python script that performs the inverse XOR operations.

wget https://artifacts.picoctf.net/c_titan/31/snake && \
python3 your_decrypt.py

Solution

  1. Step 1Recover the key
    Disassembly shows key_str being built into t_Jo3. Convert that string into a key list of ordinals.
    Learn more

    Python source files (.py) are compiled to bytecode (.pyc) by the CPython interpreter before execution. Bytecode is a lower-level, platform-independent instruction set for the Python Virtual Machine - not machine code, but not source code either. It sits in the middle: harder to read than Python, but much easier to recover than compiled C or C++.

    Tools like uncompyle6, decompile3, or pycdc can reconstruct Python source from bytecode with high fidelity. Python's built-in dis module disassembles bytecode into human-readable opcode mnemonics - useful when decompilers fail on unusual or obfuscated bytecode.

    • python3 -m dis snake - disassembles the bytecode file.
    • uncompyle6 snake - attempts full source reconstruction (install with pip install uncompyle6).
    • The key string (key_str) appears as a LOAD_CONST instruction in the disassembly - the raw string value is visible.
  2. Step 2Recreate the input list
    The bytecode stores the ciphertext integers in a list (input_list). Copy those numbers into your script.
    Learn more

    In Python bytecode, list literals are stored as a series of LOAD_CONST instructions (one per element) followed by a BUILD_LIST opcode. The disassembly makes these values directly visible - no decryption needed to extract the ciphertext list. This is a fundamental asymmetry in obfuscation via compilation: the data the program operates on must be present at runtime, so it is always recoverable from the bytecode.

    ord(c) converts a character to its ASCII integer value (e.g., ord('A') == 65). The key is stored as a string but used as a list of integers during XOR operations, so converting it with [ord(c) for c in key_str] produces the correct numeric representation.

    Recognizing that a program stores integers in a list and XORs them against a key is a pattern found constantly in CTF reversing challenges and in real malware - it is one of the simplest ways to obfuscate strings like API keys, C2 addresses, or flags without using a proper cipher.

  3. Step 3XOR decrypt
    Extend the keystream until it matches input_list length, XOR each pair, and join the characters to reveal the flag.
    result = ''.join(chr(a ^ b) for a,b in zip(input_list, key_list))
    Learn more

    XOR (exclusive OR) is the simplest symmetric cipher. XOR has a beautiful property: applying the same key twice returns the original value - m XOR k XOR k = m. This makes XOR decryption identical to encryption: just XOR the ciphertext with the same key and you recover the plaintext.

    When the key is shorter than the message, it is typically repeated cyclically - this is called a repeating-key XOR or Vigenere-like XOR. The zip function in Python pairs elements from two sequences; extending the key with itertools.cycle(key_list) creates an infinitely repeating keystream that can be zipped against any length ciphertext.

    Repeating-key XOR was used in real cryptography before modern ciphers (the Vigenere cipher is a letter-based variant). It is broken by known-plaintext attacks (if you know any bytes of the plaintext, you immediately recover the corresponding key bytes) and by frequency analysis when the key is short relative to the message. AES in CTR mode is essentially XOR with a secure, non-repeating keystream - the security comes entirely from the quality of the keystream, not the XOR operation itself.

Alternate Solution

After extracting the key string and ciphertext integers from the bytecode, use the XOR Cipher tool on this site to perform the final decryption - paste the ciphertext bytes and the key to recover the flag without writing any additional Python.

Related guides

How to Use Ghidra for Reverse Engineering CTF Challenges

Want to tackle compiled binaries next? Ghidra decompiles ELF and PE files to readable C pseudocode and is the standard free tool for CTF reverse engineering.

Flag

picoCTF{N0t_sO_coNfus1ng_sn@ke_30a...}

The decrypted string from the XOR routine is the final flag.

Want more picoCTF 2024 writeups?

Useful tools for Reverse Engineering

Related reading

What to try next