Alex vs. Base64: Cracking the Crypto Challenge at ImaginaryCTF 2024
Alex’s journey through the world of CTF challenges had taken him to new heights. After tackling the “Crash” challenge, he was ready for more. His next adventure awaited at ImaginaryCTF 2024, where a crypto challenge titled “base64” caught his eye. With 100 points up for grabs and 777 solves, it was time for Alex to put his skills to the test.
The Challenge
The challenge came with a brief description: “yet another base64 decoding challenge” and a set of files to download. Upon extracting the files, Alex found three items: main.py, out.txt and sbg.png
The main.py and PNG File
The main.py script and sbg.png provided insight into how the flag was encoded:
from Crypto.Util.number import bytes_to_long
q = 64
flag = open("flag.txt", "rb").read()
flag_int = bytes_to_long(flag)
secret_key = []
while flag_int:
secret_key.append(flag_int % q)
flag_int //= q
print(f"{secret_key = }")Explanation of the Code:
- Importing Modules: The script starts by importing
bytes_to_longfrom theCrypto.Util.numbermodule, which is used to convert bytes to a long integer. - Reading the Flag: The flag is read from
flag.txtas bytes and converted to an integer (flag_int) usingbytes_to_long. - Encoding the Flag: The flag is encoded into a list of integers (
secret_key) using a base-64 like encoding. This is done by repeatedly taking the modulus and integer division by 64 (q).
The out.txt File
The out.txt file contained the output of the main.py script:
secret_key = [10, 52, 23, 14, 52, 16, 3, 14, 37, 37, 3, 25, 50, 32, 19, 14, 48, 32, 35, 13, 54, 12, 35, 12, 31, 29, 7, 29, 38, 61, 37, 27, 47, 5, 51, 28, 50, 13, 35, 29, 46, 1, 51, 24, 31, 21, 54, 28, 52, 8, 54, 30, 38, 17, 55, 24, 41, 1]This list represented the encoded flag, broken down into base 64 components.
The Solution
Alex knew that the key to solving this challenge was to reverse the process defined in main.py. He needed to reconstruct the original flag from the secret_key.
Step-by-Step Breakdown
- Initialize: Start with
flag_intas 0. - Reconstruct
flag_int: Use the values insecret_keyto rebuild the integer representation of the flag. - Convert to Bytes: Once
flag_intis reconstructed, convert it back to bytes to reveal the flag.
The Solution Script
Alex wrote the following script to achieve this:
from Crypto.Util.number import long_to_bytes
secret_key = [10, 52, 23, 14, 52, 16, 3, 14, 37, 37, 3, 25, 50, 32, 19, 14, 48, 32, 35, 13, 54, 12, 35, 12, 31, 29, 7, 29, 38, 61, 37, 27, 47, 5, 51, 28, 50, 13, 35, 29, 46, 1, 51, 24, 31, 21, 54, 28, 52, 8, 54, 30, 38, 17, 55, 24, 41, 1]
q = 64
flag_int = 0
for value in reversed(secret_key):
flag_int = flag_int * q + value
flag = long_to_bytes(flag_int)
print(flag)Explanation of the Solution Script:
- Importing Modules: The script starts by importing
long_to_bytesfrom theCrypto.Util.numbermodule, which is used to convert a long integer back to bytes. - Initializing Variables: The list
secret_keyis defined with the values fromout.txt, andqis set to 64. - Reconstructing the Integer: Starting with
flag_intas 0, the script iterates over the reversedsecret_keylist, reconstructing the originalflag_intby multiplying byqand adding the current value. - Converting to Bytes: The reconstructed integer (
flag_int) is converted back to bytes usinglong_to_bytes, revealing the flag.
The Moment of Triumph
With anticipation building, Alex ran his solution script. The screen displayed a stream of bytes that slowly transformed into a readable string. Finally, the flag was revealed:
b'ictf{b4se_c0nv3rs1on_ftw_236680982d9e8449}\n'Alex’s persistence and methodical approach had paid off once again. He submitted the flag and watched as his score climbed higher.
Conclusion
This adventure was yet another testament to Alex’s growing expertise in cryptography. The challenge of reversing the encoding process and retrieving the flag added a new layer of excitement to his journey. With each challenge conquered, Alex’s passion for cybersecurity grew stronger, fueling his drive to master the art of cryptographic puzzles.
