# 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 ```bash # Terminal 1 — TX (read output) nc 1111 # Terminal 2 — RX (send commands) nc 2222 ``` Read the ESP32 boot sequence on TX carefully — it contains hints. ![TX terminal showing ESP32 boot sequence with diagnostic messages](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/hate_uart_boot.png) ### Step 2 — Discover hidden commands ```text help ``` Only basic commands shown. But sending `?` or `help -a` reveals hidden ones: ```text ? >> 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: ```text 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` ```python import base64 base64.b64decode("dGgzcmFweV9tMGR1bGU9") # b'th3rapy_m0dule=' ``` ![mem read output showing base64 token in ASCII column](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/hate_uart_mem.png) ### Step 4 — Authenticate as debug user ```text debug auth th3rapy_m0dule= ``` Response: `DEBUG MODE ENABLED. Extended commands unlocked.` ### Step 5 — Read the NVS flag List NVS entries: ```text nvs list ``` Entry `crypto_flag` appears (blob, 34 bytes). Read it: ```text nvs read crypto_flag ``` Returns a hexdump of the XOR-encrypted flag blob. ![nvs read showing the encrypted flag hexdump](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/hate_uart_nvs.png) ### 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`. ```python 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} ``` ![Python decryption script printing the flag](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/hate_uart_decrypt.png) --- ## Flag `ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}`