3.8 KiB
3.8 KiB
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
# Terminal 1 : TX (lecture)
nc <host> 1111 | tee flash_output.txt
# Terminal 2 : RX (écriture)
echo "dump_flash" | nc <host> 2222
Le dump est envoyé en base64. Extraire et décoder :
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
# 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
# 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
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
- Ouvrir Ghidra, importer
app_firmware.bin(ou mieux, l'ELF si disponible) - Architecture : Xtensa:LE:32:default
- Analyser → chercher
app_maindans les symboles - Suivre les appels :
app_main()→wired_med_crypto_init()→mbedtls_aes_setkey_enc() - Les arguments de
mbedtls_aes_setkey_enc()pointent verstherapy_aes_keydans.rodata - 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
# 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
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