Files
HIP7CTF_Writeups/reversible_logic.md
m0rph3us1987 a79656b647 Added writeups
2026-03-08 12:22:39 +01:00

3.1 KiB

Reversible Logic

Reversible Logic is a cryptography challenge based on the properties of the XOR operation. We are provided with a service that encrypts our input using a hidden flag as the key.

Information Gathering

We connect to the challenge service and are greeted with a prompt:

--- Secure XOR Encryption Service ---
Enter a message to encrypt: 

The description states: "This program implements a simple XOR cipher using a hidden flag as the key."

Let's test it by sending a simple input, like "AAAA":

Enter a message to encrypt: AAAA

Encrypted Result (Hex): 3a272d20

Vulnerability Analysis

The service implements a standard XOR cipher where:

Ciphertext = Plaintext \oplus Key

We control the Plaintext (our input) and we receive the Ciphertext (the hex output). The Key is the hidden flag we want to recover.

A fundamental property of the XOR operation is that it is its own inverse (reversible):

A \oplus B = C \implies C \oplus B = A

Therefore, we can recover the Key by XORing the Ciphertext with our Known Plaintext:

Key = Ciphertext \oplus Plaintext

To recover the full flag, we just need to send a plaintext that is at least as long as the flag. Since we don't know the exact length, sending a long string (e.g., 100 characters) ensures we cover it entirely.

Solution

We can automate this process with a Python script:

  1. Connect to the server.
  2. Send a long string of known characters (e.g., 100 'A's).
  3. Receive the hex-encoded ciphertext.
  4. Decode the hex and XOR it with our string of 'A's to reveal the flag.

Solver Script

from pwn import *

# Set the log level so we can see the "Opening connection" messages
context.log_level = 'info'

def main():
    # 1. Connect to the challenge instance
    #    (Matches the IP/Port from your previous message)
    io = remote('127.0.0.1', 1315)

    # 2. Handle the server prompts
    #    We read until the server asks for input
    io.recvuntil(b"Enter a message to encrypt: ")

    # 3. Send our "Known Plaintext"
    #    We send a long string of 'A's (0x41) to ensure we capture the full flag.
    #    If the flag is longer than 100 chars, just increase this number.
    plaintext = b"A" * 100
    io.sendline(plaintext)

    # 4. Receive the response
    io.recvuntil(b"Encrypted Result (Hex): ")
    
    #    Read the hex string line and strip whitespace/newlines
    hex_output = io.recvline().strip().decode()
    
    log.info(f"Received Hex Ciphertext: {hex_output}")

    # 5. Decode the Hex
    cipher_bytes = bytes.fromhex(hex_output)

    # 6. XOR to recover the key
    #    pwntools has a built-in xor() function that is very robust.
    #    Logic: Key = Cipher ^ Plaintext
    recovered_key = xor(cipher_bytes, plaintext)

    # 7. Output the Flag
    #    We use 'errors=ignore' just in case of weird bytes, 
    #    but for a text flag it should be clean.
    log.success(f"Recovered Flag: {recovered_key.decode('utf-8', errors='ignore')}")

    io.close()

if __name__ == "__main__":
    main()

Execution

Running the logic manually or via script reveals the flag. {flag: xor_logic_is_reversible_123}