- Generated screenshots for all 33 challenges (ESP, Hardware, IoT, OT, Misc, Web3) - Replaced all 123 placeholder lines with actual PNG image references - Cleaned duplicate images from previously partial updates - All write-ups now have full illustrated solutions |
||
|---|---|---|
| .. | ||
| README.md | ||
Let's All Hate UART
| Field | Value |
|---|---|
| Category | IoT |
| Difficulty | Medium-Hard |
| Points | 500 |
| Author | Eun0us |
| CTF | Espilon 2026 |
Description
Chapter 1 — Peripheral Access
In the basement of Sainte-Mika Clinic, you have gained physical access to a WIRED-MED therapy module. You have identified the UART pads on the PCB. Connect and explore this embedded device — it hides far more than it shows.
"Let's all love Lain... but let's all hate UART debug interfaces left open in production."
- TX (read):
nc CHALLENGE_HOST 1111 - RX (write):
nc CHALLENGE_HOST 2222
TL;DR
Connect to the split UART, spot hidden commands by sending ? or help -a. Read memory
at address 0x3FFB0800 to find a base64-encoded debug token (th3rapy_m0dule=). Authenticate
with it to unlock extended commands. List and read the NVS crypto_flag blob. XOR-decrypt
with key WIRED to get the flag.
Tools
| Tool | Purpose |
|---|---|
nc |
Split UART connection |
| Python 3 | Base64 decode and XOR decryption |
Solution
Step 1 — Connect
# Terminal 1 — TX (read output)
nc <host> 1111
# Terminal 2 — RX (send commands)
nc <host> 2222
Read the ESP32 boot sequence on TX carefully — it contains hints.
Step 2 — Discover hidden commands
help
Only basic commands shown. But sending ? or help -a reveals hidden ones:
?
>> Extended commands: debug, mem, nvs, flash
The info command also hints: Debug interface: ENABLED (restricted)
Step 3 — Extract the debug token from RAM
The public DRAM range 0x3FFB0000–0x3FFB1000 is readable without authentication:
mem read 0x3FFB0800 48
Output:
3FFB0800: 57 49 52 45 44 2D 4D 45 44 00 00 00 00 00 00 00 |WIRED-MED.......|
3FFB0810: 64 47 68 33 63 6D 46 77 65 56 39 74 4D 47 52 31 |dGgzcmFweV9tMGR1|
3FFB0820: 62 47 55 39 00 00 00 00 00 00 00 00 00 00 00 00 |bGU9............|
The ASCII at offsets 0x810–0x830 is base64: dGgzcmFweV9tMGR1bGU9
import base64
base64.b64decode("dGgzcmFweV9tMGR1bGU9")
# b'th3rapy_m0dule='
Step 4 — Authenticate as debug user
debug auth th3rapy_m0dule=
Response: DEBUG MODE ENABLED. Extended commands unlocked.
Step 5 — Read the NVS flag
List NVS entries:
nvs list
Entry crypto_flag appears (blob, 34 bytes).
Read it:
nvs read crypto_flag
Returns a hexdump of the XOR-encrypted flag blob.
Step 6 — Decrypt with XOR key WIRED
The key is WIRED (5 bytes). Hint: the flag starts with ESPILON{ — XOR the first 5
bytes of the ciphertext with ESPIO to confirm the key is WIRED.
encrypted = bytes.fromhex("...") # hex from nvs read
key = b"WIRED"
flag = bytes(b ^ key[i % len(key)] for i, b in enumerate(encrypted))
print(flag.decode())
# ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}
Flag
ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}



