← Back to list

RCSC Salami Contest 2025

Cryptography: Simple as you like

MrX · 2025-04-04 15:27 · 0 claps · 1.5 min read
#crypto #cryptography #xor
Open on Medium ↗
Wiki topics: CRY · Crypto & Web3 🔒 · Cybersecurity

RCSC Salami Contest 2025

Cryptography: Simple as you like

Contest file: crypto_easy.zip

After analyzing the source code, you may discover that the flag is XORed with a randomly generated key of length 5. Since the key is random, recovering the exact key directly would be quite challenging.

However, we know that all flags follow the format rcscsalamictf{some_text}, meaning the first fourteen bytes of the plaintext are always rcscsalamictf{. This allows us to recover the first fourteen bytes of the key by XORing them with the corresponding encrypted bytes.

For the remaining fifteenth and sixteenth byte of the key, we can brute-force all possible values.

This script will bruteforce all possible value and then save to recovered_keys.txt file.

def recover_key(enc, known_plaintext):
    key = bytearray(len(known_plaintext))
    for i in range(len(known_plaintext)):
        key[i] = enc[i] ^ known_plaintext[i]  
    return key

def bruteforce_15_16_byte(enc, known_plaintext):
    with open("recovered_keys.txt", "w") as f:
        for i in range(32, 127):  # for 15th byte
            for j in range(32, 127):  # for 16th byte
                candidate_plaintext = known_plaintext + bytes([i, j])
                recovered_key_part = recover_key(enc[:16], candidate_plaintext)
                result = f"{recovered_key_part.hex()}\n"
                f.write(result)


known_plaintext = b'rcscsalamictf{'  # The first 14 characters of the original message
enc = bytes.fromhex("5dfa063ecd32c430ade4e1b70ba91eda7dc6442ee13d98259fbef4a61fab76841cbe0602dd26d80ef0ebdd975ee619885aed2a3e8e3dcf23f4f9b1b032b4769870e04528cc0cdb24a3eee7b01eaf")  # Replace with actual encrypted data

bruteforce_15_16_byte(enc, known_plaintext)

Using each potential key, we will decrypt the flag and obtain multiple possible outputs. Here is the script:

def xor_decrypt(ciphertext, key):
    """XOR the ciphertext with the given key."""
    decrypted = bytearray()
    for i in range(len(ciphertext)):
        decrypted.append(ciphertext[i] ^ key[i % len(key)])
    return bytes(decrypted)

def try_decrypt_with_keys(encrypted_hex, keys_hex, output_file):
    """Try to decrypt the encrypted text with all given keys and save results."""
    encrypted_data = bytes.fromhex(encrypted_hex)

    with open(output_file, "w", encoding="utf-8") as f:
        for key_hex in keys_hex:
            key = bytes.fromhex(key_hex)
            decrypted_data = xor_decrypt(encrypted_data, key)

            try:
                decrypted_text = decrypted_data.decode('utf-8')
                result = f"Decrypted with key {key_hex}: {decrypted_text}\n"
            except UnicodeDecodeError:
                result = f"Decrypted with key {key_hex}: (binary output) {decrypted_data.hex()}\n"

            print(result.strip())
            f.write(result)

if __name__ == '__main__':
    encrypted_hex = "5dfa063ecd32c430ade4e1b70ba91eda7dc6442ee13d98259fbef4a61fab76841cbe0602dd26d80ef0ebdd975ee619885aed2a3e8e3dcf23f4f9b1b032b4769870e04528cc0cdb24a3eee7b01eaf"

    with open("recovered_keys.txt", "r") as file:
        keys_hex = [line.strip() for line in file.readlines() if line.strip()]

    try_decrypt_with_keys(encrypted_hex, keys_hex, "decrypted_output.txt")

Since all valid flags follow the standard rcscsalamictf{…} format, we can manually analyze the results to identify the correct flag.

flag is marked here

flag is marked here

After analyzing you can find the correct flag.


메타데이터
post_id
c46a4c11706d
slug
rcsc-salami-contest-2025-c46a4c11706d
url
https://medium.com/@MrX2025/rcsc-salami-contest-2025-c46a4c11706d
canonical_url
https://medium.com/@MrX2025/rcsc-salami-contest-2025-c46a4c11706d
author_url
https://medium.com/@MrX2025
status
ok
fetched_at
2026-06-15 20:49:13