# LAIN_Br34kC0r3 V2 — Solution **Chapitre 2 : Core Analysis** | Difficulté : Hard | Flag : `ESPILON{3sp32_fl4sh_dump_r3v3rs3d}` ## Overview Ce challenge fournit un dump flash complet d'un ESP32 (bootloader + partition table + NVS + firmware applicatif). Le joueur doit extraire le firmware, le reverse engineer pour trouver les clés AES-256-CBC, puis déchiffrer le flag stocké dans la NVS. ## Étape 1 — Récupérer le dump flash ```bash # Terminal 1 : TX (lecture) nc 1111 | tee flash_output.txt # Terminal 2 : RX (écriture) echo "dump_flash" | nc 2222 ``` Le dump est envoyé en base64. Extraire et décoder : ```python import base64 with open("flash_output.txt") as f: lines = f.readlines() # Extract base64 lines between markers b64_data = "" capture = False for line in lines: if "BEGIN FLASH DUMP" in line: capture = True continue if "END FLASH DUMP" in line: break if capture: b64_data += line.strip() flash = base64.b64decode(b64_data) with open("flash_dump.bin", "wb") as f: f.write(flash) ``` ## Étape 2 — Analyse du dump flash ```bash # Identifier les composants binwalk flash_dump.bin # Ou utiliser esptool esptool.py image_info --version 2 flash_dump.bin ``` Structure identifiée : ``` 0x0000 Padding (0xFF) 0x1000 ESP32 bootloader (magic 0xE9) 0x8000 Partition table 0x9000 NVS partition (24 KiB) 0xF000 PHY init data 0x10000 Application firmware (magic 0xE9) ``` ## Étape 3 — Extraire le firmware applicatif ```bash # Extraire l'app à partir de l'offset 0x10000 dd if=flash_dump.bin of=app_firmware.bin bs=1 skip=$((0x10000)) # Vérifier file app_firmware.bin # Devrait montrer un binaire ESP32 ou "data" hexdump -C app_firmware.bin | head -5 # Premier byte devrait être 0xE9 (ESP image magic) ``` ## Étape 4 — Reverse Engineering ### Méthode rapide : strings ```bash strings -n 10 app_firmware.bin | grep -i "key\|aes\|iv\|wired\|therapy" ``` Résultats attendus : ``` W1R3D_M3D_TH3R4PY_K3Y_2024_L41N! # AES-256 key (32 bytes) L41N_WIRED_IV_01 # AES IV (16 bytes) WIRED-MED Therapy Module ``` ### Méthode complète : Ghidra 1. Ouvrir Ghidra, importer `app_firmware.bin` (ou mieux, l'ELF si disponible) 2. Architecture : **Xtensa:LE:32:default** 3. Analyser → chercher `app_main` dans les symboles 4. Suivre les appels : `app_main()` → `wired_med_crypto_init()` → `mbedtls_aes_setkey_enc()` 5. Les arguments de `mbedtls_aes_setkey_enc()` pointent vers `therapy_aes_key` dans `.rodata` 6. Extraire les 32 bytes de la clé et les 16 bytes de l'IV ## Étape 5 — Récupérer le flag chiffré ### Option A : Commande directe ``` encrypted_data ``` → Retourne le ciphertext en hex ### Option B : Parser la NVS ```bash # Extraire la partition NVS dd if=flash_dump.bin of=nvs_dump.bin bs=1 skip=$((0x9000)) count=$((0x6000)) # Utiliser nvs_tool.py de ESP-IDF (si disponible) python3 $IDF_PATH/components/nvs_flash/nvs_partition_tool/nvs_tool.py --dump nvs_dump.bin ``` Chercher l'entrée : namespace `wired_med`, key `encrypted_flag`, type blob ## Étape 6 — Déchiffrement AES-256-CBC ```python from Crypto.Cipher import AES from Crypto.Util.Padding import unpad key = b"W1R3D_M3D_TH3R4PY_K3Y_2024_L41N!" # 32 bytes iv = b"L41N_WIRED_IV_01" # 16 bytes # Ciphertext from encrypted_data command or NVS ciphertext = bytes.fromhex("...") cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) print(plaintext.decode()) # ESPILON{3sp32_fl4sh_dump_r3v3rs3d} ``` ## Résumé de la chaîne d'attaque ``` dump_flash → base64 decode → binwalk → extract app @ 0x10000 → strings/Ghidra (Xtensa RE) → find AES key + IV in .rodata → encrypted_data (or NVS parse) → AES-256-CBC decrypt → FLAG ``` ## Script de solve complet Voir `solve/solve.py`