← All write-ups
May 1, 2025HIGH0-DAY

Secure boot contourné : root par l'UART sur une passerelle ARM

2025 · Client E · Industrial IoT & embedded systems

Recherche personnelle de 34zY / Hamza Terir sur du matériel COTS (SoC ARM i.MX8, chaîne U-Boot / HAB). Client final anonymisé. Exploit développé from scratch (automatisation série sur le port UART).

Contexte

Passerelle de communication pour environnement industriel, bâtie sur un SoC ARM Cortex-A53 (famille NXP i.MX8) avec secure boot HAB (High Assurance Boot) : une chaîne de confiance signée où chaque étage vérifie le suivant, du ROM jusqu’au noyau. Objectif de l’équipement : garantir que seul un firmware signé démarre.

Comment je l’ai trouvée

Avec l’accès physique prévu au périmètre, j’ai inspecté le PCB à la recherche d’interfaces de debug. Un port série UART était accessible physiquement, exposé jusqu’à un connecteur externe (115200 baud). En écoutant la liaison au démarrage, la console du bootloader s’affichait, avec la fenêtre classique « appuyez sur une touche pour stopper l’autoboot ».

J’ai obtenu un shell U-Boot (Hush) et cartographié la couverture de la chaîne de confiance : le noyau et son device tree étaient bien signés et vérifiés par HAB, mais ni les arguments passés au noyau (bootargs), ni le script de démarrage (boot.scr) n’étaient couverts.

Vérification technique

La collecte publique reste limitée à l’analyse d’une image de laboratoire et à la configuration de boot :

sha256sum fixtures/firmware.bin
strings -n 8 fixtures/firmware.bin | rg -i 'secure|boot|uart|debug|recovery'

Le contrôle de release doit vérifier que les variables de boot sensibles ne sont pas modifiables sans authentification et que l’image est signée avant exécution :

def boot_policy(*, secure_boot: bool, debug_uart: bool, image_verified: bool) -> None:
    if not secure_boot or debug_uart or not image_verified:
        raise ValueError("boot trust policy is not satisfied")

Le retest documente l’état avant/après, sans publier de séquence de modification ou de clé réelle.

La faille

Le secure boot vérifie les binaires (noyau, DTB) mais pas la configuration de boot. Depuis la console U-Boot non protégée, j’ai réécrit l’argument désignant le premier processus du système :

setenv bootargs '... root=/dev/mmcblk2p2 rw init=/bin/bash'
ext4load mmc 2:2 ${loadaddr} /boot/Image
ext4load mmc 2:2 ${fdt_addr} /boot/<dtb>
booti ${loadaddr} - ${fdt_addr}

Le noyau démarre, HAB valide sa signature (la chaîne reste techniquement respectée sur le binaire), puis honore init=/bin/bash : PID 1 devient un shell root interactif, sans login ni authentification. C’est le gap classique « verified boot, unverified boot config ». Hypothèse cassée : « si le noyau est signé, le système démarré est de confiance ».

Impact

CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H = 8.4 (High).

Remédiation

CWE-306 (Missing Authentication for Critical Function) · CWE-347 (Improper Verification of Cryptographic Signature).