ESPILON-CTF-2026-Writeups/IoT/Lets_All_Hate_UART
2026-03-22 19:18:58 +01:00
..
README.md ESPILON CTF 2026 — Write-ups édition 1 (33 challenges) 2026-03-22 19:18:58 +01:00

Let's All Hate UART — Solution

Chapitre 1 : Peripheral Access | Difficulté : Medium-Hard | Flag : ESPILON{u4rt_nvs_fl4sh_d1sc0v3ry}

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.

Étape 1 — Connexion UART

Ouvrir deux terminaux :

# Terminal 1 : TX (lecture seule)
nc <host> 1111

# Terminal 2 : RX (écriture seule)
nc <host> 2222

Le boot sequence ESP32 s'affiche sur TX. Lire attentivement — il contient des infos cruciales.

Étape 2 — Discovery des commandes cachées

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.

mem read 0x3FFB0800 48

Résultat :

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

import base64
base64.b64decode("dGgzcmFweV9tMGR1bGU9")
# b'th3rapy_m0dule='

Étape 4 — Authentification debug

debug auth th3rapy_m0dule=

→ "DEBUG MODE ENABLED. Extended commands unlocked."

Étape 5 — Exploration NVS

nvs list

Affiche les entrées NVS dont crypto_flag (blob, 34 bytes).

nvs read crypto_flag

Retourne un hexdump du flag chiffré.

Étape 6 — Déchiffrement XOR

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é.

encrypted = bytes.fromhex("...")  # hex du 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

Voir solve/solve.py