From 0c830213914a84449c690d2296e9b8ce2b232d53 Mon Sep 17 00:00:00 2001 From: Eun0us Date: Thu, 26 Mar 2026 17:33:34 +0000 Subject: [PATCH] write-up: IoT/Lets_All_Hate_UART/README.md --- IoT/Lets_All_Hate_UART/README.md | 127 +++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/IoT/Lets_All_Hate_UART/README.md b/IoT/Lets_All_Hate_UART/README.md index 3a5b869..89d6fe8 100644 --- a/IoT/Lets_All_Hate_UART/README.md +++ b/IoT/Lets_All_Hate_UART/README.md @@ -1,46 +1,96 @@ -# Let's All Hate UART — Solution +# Let's All Hate UART -**Chapitre 1 : Peripheral Access** | Difficulté : Medium-Hard | Flag : `ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}` +| Field | Value | +|-------|-------| +| Category | IoT | +| Difficulty | Medium-Hard | +| Points | 500 | +| Author | Eun0us | +| CTF | Espilon 2026 | -## Overview +--- -Ce challenge simule l'interface UART d'un module de thérapie WIRED-MED (ESP32). Le joueur doit progresser à travers 4 couches de discovery pour extraire le flag depuis la NVS du device. +## Description -## Étape 1 — Connexion UART +**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 -Ouvrir deux terminaux : ```bash -# Terminal 1 : TX (lecture seule) +# Terminal 1 — TX (read output) nc 1111 -# Terminal 2 : RX (écriture seule) +# Terminal 2 — RX (send commands) nc 2222 ``` -Le boot sequence ESP32 s'affiche sur TX. Lire attentivement — il contient des infos cruciales. +Read the ESP32 boot sequence on TX carefully — it contains hints. -## Étape 2 — Discovery des commandes cachées +> 📸 `[screenshot: TX terminal showing ESP32 boot sequence with diagnostic messages]` -La commande `help` ne montre que les commandes basiques. Deux indices : -- `info` mentionne "Debug interface: ENABLED (restricted)" -- Envoyer `?` ou `help -a` révèle les commandes cachées : `debug`, `mem`, `nvs`, `flash` - -## Étape 3 — Extraction du token debug depuis la RAM - -La commande `mem read` fonctionne SANS authentification pour la plage DRAM publique `0x3FFB0000-0x3FFB1000`. +### 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 ``` -Résultat : +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............| ``` -La partie ASCII aux offsets 0x810-0x830 contient du base64 : `dGgzcmFweV9tMGR1bGU9` +The ASCII at offsets 0x810–0x830 is base64: `dGgzcmFweV9tMGR1bGU9` ```python import base64 @@ -48,40 +98,53 @@ base64.b64decode("dGgzcmFweV9tMGR1bGU9") # b'th3rapy_m0dule=' ``` -## Étape 4 — Authentification debug +> 📸 `[screenshot: mem read output showing base64 token in ASCII column]` -``` +### Step 4 — Authenticate as debug user + +```text debug auth th3rapy_m0dule= ``` -→ "DEBUG MODE ENABLED. Extended commands unlocked." +Response: `DEBUG MODE ENABLED. Extended commands unlocked.` -## Étape 5 — Exploration NVS +### Step 5 — Read the NVS flag -``` +List NVS entries: + +```text nvs list ``` -Affiche les entrées NVS dont `crypto_flag` (blob, 34 bytes). +Entry `crypto_flag` appears (blob, 34 bytes). -``` +Read it: + +```text nvs read crypto_flag ``` -Retourne un hexdump du flag chiffré. +Returns a hexdump of the XOR-encrypted flag blob. -## Étape 6 — Déchiffrement XOR +> 📸 `[screenshot: nvs read showing the encrypted flag hexdump]` -Le blob est XOR'd avec la clé cyclique `WIRED` (5 bytes). Indice : le flag commence par `ESPILON{` — en XOR avec les premiers bytes du blob, on peut retrouver la clé. +### 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 du nvs read +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} ``` -## Script de solve complet +> 📸 `[screenshot: Python decryption script printing the flag]` -Voir `solve/solve.py` +--- + +## Flag + +`ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}`