Pocket CTF Box: Hex Speak - Cryptography Writeup Report
Case ID: BB-CRYPTO-2026-0201
Classification: Cryptography - Obfuscated Flag Recovery (XOR + Hex Encoding)
Evidence: dump_hard.txt
Date of Analysis: 2026-02-01
Challenge Link: https://learn.hacklido.com/challenges/hex-speak

1. Executive Summary
A system log entry captured a suspicious memory dump containing an obfuscated string. Per the log’s own note, the flag was XOR-obfuscated before being hex-encoded, in an attempt to avoid the “too obvious” mistake of logging a flag in plain hex after a prior breach. Reversing both layers, hex decode followed by a single-byte XOR brute force, recovers the original flag.
Verdict: Recovered flag is HackCTF{m3m_l34k_r3v3rs3}, obtained with XOR key 0x13.
2. Tools Used
| Tool | Purpose |
Python 3 (bytes.fromhex) | Hex decoding of the dumped string |
| Python 3 (brute-force loop) | Single-byte XOR key recovery |
CyberChef (From Hex + XOR Brute Force) | Alternative no-code verification path, per the challenge’s own hints |
3. Methodology - Step by Step
Step 1: Identify the encoding layers
The log entry itself gives this away directly:
NOTE:
Developer tried to hide sensitive flag using XOR before dumping into hex.
So the transformation chain applied to the original flag was:
plaintext flag -> XOR with single-byte key -> hex-encode -> logged as DEBUG_SECURE_DUMP
To recover the flag, the same steps must be reversed in the opposite order: hex-decode first, then XOR-decode.
The dumped string, confirmed by Hint 1 and Hint 2 to be standard hex (two characters per byte), is:
5B727078504755687E207E4C7F2027784C612065206160206E
Step 2: Hex-decode the dumped string
hex_str = "5B727078504755687E207E4C7F2027784C612065206160206E"
data = bytes.fromhex(hex_str)
print(data)
Output:
b"[rpxPGUh~ ~L\x7f 'xLa e a` n"
This is 26 bytes of unreadable, XOR-scrambled data, confirming the hex layer decodes cleanly but a second layer of obfuscation (the XOR) is still in place underneath it.
CyberChef equivalent: drop the hex string into the input, add a From Hex operation, and observe the same garbled 26-byte output.
Step 3: Brute-force the single-byte XOR key
Since the note specifies “a simple XOR obfuscation,” a single repeating byte key is assumed rather than a multi-byte key. All 256 possible byte values (0x00 to 0xFF) are tried against the decoded bytes, and the output is checked for a readable flag pattern:
for k in range(256):
out = bytes([b ^ k for b in data])
if b"HackCTF" in out:
print(k, out)
Output:
19 b'HackCTF{m3m_l34k_r3v3rs3}'
Key 19 (0x13) is the only value out of all 256 that produces a clean, readable ASCII string beginning with HackCTF{, every other key produces unprintable or nonsensical output. This confirms 0x13 as the correct XOR key.
CyberChef equivalent: after From Hex, chain an XOR Brute Force operation with a HackCTF crib string set as the search filter, it will highlight key 13 (hex) as the matching result. Alternatively, add a manual XOR operation with key 13 (hex) directly after From Hex once the key is known.
Step 4: Recover the flag
hex_str = "5B727078504755687E207E4C7F2027784C612065206160206E"
data = bytes.fromhex(hex_str)
flag = bytes([b ^ 0x13 for b in data])
print(flag.decode())
Output:
HackCTF{m3m_l34k_r3v3rs3}
4. Consolidated Findings
| Step | Value |
|—|—|
| Raw dumped string | 5B727078504755687E207E4C7F2027784C612065206160206E |
| After hex decode | [rpxPGUh~ ~L\x7f 'xLa e a n(unreadable) |
| XOR key recovered |0×13(decimal 19) |
| Recovered flag |HackCTF{m3m_l34k_r3v3rs3}` |
5. Recommendations
- Never log sensitive values, even obfuscated ones, XOR with a single repeating byte is trivially brute-forceable (only 256 possibilities) and offers no real security, only a false sense of one.
- If obfuscation of logged data is unavoidable, use a proper encryption scheme (e.g. AES-GCM) with a securely managed key, not a reversible bitwise transform.
- Treat any “DEBUG” or diagnostic dump path as a potential data-leakage vector; ensure secrets are redacted before they ever reach a log sink, rather than relying on obfuscation after the fact.
- Rotate any credential or flag value that was exposed through this log, since the encoding was reversible with negligible effort.