Reverse Me
Reverse Me
Platform: taipanbyte | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-02-14 | Status: Solved Techniques: identity_transform_detection, static_string_extraction, xor_cancellation
Summary
Task: ELF binary that checks a flag using XOR and hex encoding. Solution: Recognized that double XOR with same key and hex encode/decode pair form an identity function, so the hardcoded string in .rodata is the flag.
Reverse Me — TaipanByte CTF
Description
We found a binary that checks a flag. The program takes a string, does something with it, and reports whether the flag is correct or not. Find the flag.
Files: secret.tb — ELF 64-bit LSB PIE executable, x86-64, dynamically linked, not stripped
Analysis
Step 1: File Identification
bash read-only • copy allowedfile secret.tb # secret.tb: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped
The binary is not stripped — all symbols are present, which significantly simplifies analysis.
Step 2: String Search
bash read-only • copy allowedstrings secret.tb # ... # Enter flag: # TB{REDACTED} # Correct! Flag is ... # Wrong! # %02x # ...
A suspicious string TB{REDACTED} is immediately visible in the .rodata section. But we need to verify that this is actually the flag and not a decoy.
Step 3: Static Analysis of the Algorithm
Using objdump and radare2, the complete program logic was reconstructed:
3.1 Input
The program outputs "Enter flag: " and reads user input via getline.
3.2 First XOR Loop
Loads the hardcoded string TB{REDACTED} from .rodata and XORs each byte with key 0x42:
for i in range(len(s)):
s[i] ^= 0x42
3.3 Hex Encoding
Each XORed byte is converted to a 2-character hex string via snprintf("%02x", ...):
byte 0x16 → "16"
byte 0x00 → "00"
...
3.4 hex_decode Function
The hex string is converted back to raw bytes — complete inversion of the previous step:
"16" → byte 0x16
"00" → byte 0x00
...
3.5 Second XOR Loop
Each decoded byte is XORed again with 0x42 — complete inversion of the first XOR:
for i in range(len(s)):
s[i] ^= 0x42
3.6 Comparison
The result is compared with user input. If it matches — "Correct!".
Step 4: Mathematical Proof
The entire transformation chain is an identity function:
input → XOR(0x42) → hex_encode → hex_decode → XOR(0x42) → output
XOR(XOR(x, 0x42), 0x42) = x (XOR property: a ⊕ b ⊕ b = a)
hex_decode(hex_encode(x)) = x (inverse operations)
Result: output = input
The obfuscation is a red herring. The expected input = the original hardcoded string.
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ Reverse Me — TaipanByte CTF Proof that the transformation is an identity function. """ # Hardcoded string from .rodata flag = "TB{REDACTED}" # Verify: XOR → hex_encode → hex_decode → XOR = identity key = 0x42 # Step 1: XOR with 0x42 xored = bytes([b ^ key for b in flag.encode()]) print(f"After XOR(0x42): {xored.hex()}") # Step 2: hex_encode (already done by .hex()) hex_encoded = xored.hex() print(f"After hex_encode: {hex_encoded}") # Step 3: hex_decode hex_decoded = bytes.fromhex(hex_encoded) print(f"After hex_decode: {hex_decoded.hex()}") # Step 4: XOR with 0x42 again result = bytes([b ^ key for b in hex_decoded]) print(f"After XOR(0x42): {result.decode()}") # Verify: result == original string assert result.decode() == flag print(f"\nFlag: {flag}")
Tools
| Tool | Usage |
|---|---|
| file | Binary type identification |
| strings | Search for readable strings in .rodata |
| objdump | Disassembly for flow analysis |
| radare2 | Detailed static analysis of functions |
| xxd | Viewing hex dump of sections |
| Python 3 | Algorithm verification and identity proof |
Techniques
- XOR Cancellation — double XOR with the same key = identity (a ⊕ k ⊕ k = a)
- Static String Extraction — extracting hardcoded strings from .rodata
- Identity Transform Detection — recognizing chains of operations that mutually cancel out