Le reverse engineering de firmware IoT permet d'identifier des vulnérabilités critiques — credentials hardcodés, services non sécurisés, clés privées embarquées — avant que des attaquants ne les exploitent. Ce guide couvre les méthodes d'extraction physique (JTAG, UART, SPI flash dump) et logicielle, l'analyse statique avec Binwalk, la décompilation avec Ghidra, l'émulation avec QEMU et Firmadyne, avec les commandes exactes et des exemples basés sur des CVE réels de l'écosystème routeur/caméra/PLC.

Chaque routeur domestique, chaque caméra IP, chaque automate industriel embarque un firmware qui n'a jamais été audité. Ce n'est pas une hypothèse — c'est une certitude statistique dans un écosystème où des centaines de fabricants produisent des dérivés de la même base OpenWrt ou uClibc sans jamais ouvrir leur code au regard extérieur. Le reverse engineering firmware IoT est la discipline qui change cette équation : elle permet d'extraire ce code, de l'analyser, d'identifier les vulnérabilités critiques (credentials par défaut hardcodés, clés privées TLS embarquées, backdoors constructeur), et de les divulguer responsablement avant qu'un groupe comme Mirai ou ses successeurs ne les transforme en botnets de 500 000 nœuds. Ce guide couvre l'intégralité de la chaîne — de l'extraction physique par JTAG et UART jusqu'à l'émulation complète avec QEMU et Firmadyne, en passant par l'analyse statique avec Binwalk et la décompilation avec Ghidra. Les exemples s'appuient sur des CVE réels documentés par l'ENISA et le NIST, sur des architectures MIPS et ARM courantes, et sur des commandes reproductibles dans un lab isolé. Uniquement sur dispositifs personnels ou dans le cadre d'un mandat explicitement autorisé.

À retenir

  • Binwalk -eM est votre première étape systématique : l'extraction récursive révèle les systèmes de fichiers, les clés SSH, et les scripts d'init — en moins de 30 secondes sur la plupart des firmwares routeurs.
  • Les credentials hardcodés restent la vulnérabilité n°1 : dans 60%+ des firmwares IoT audités, strings + grep sur le binaire extrait révèle des mots de passe en clair ou des clés API dans les 10 premières minutes.
  • Ghidra script Python multiplie la productivité par 10 : automatiser la recherche des fonctions d'authentification (strcmp, strcasecmp, strncmp sur des chaînes fixées) élimine les faux positifs manuels.
  • L'émulation QEMU révèle des vulnérabilités invisibles à l'analyse statique : les race conditions, les buffer overflows sur les chemins de code dynamiques, et les comportements des daemons réseau ne se voient qu'en exécution.
  • NIST SP 800-213 et ENISA IoT définissent le cadre légal : la divulgation coordonnée (90 jours) protège le chercheur et pousse les fabricants à patcher.

Comment extraire un firmware IoT : méthodes physiques et logicielles ?

Deux grandes familles d'approches existent pour obtenir le firmware d'un dispositif IoT. Le choix dépend du dispositif, de votre accès physique, et du niveau de protection du fabricant.

Méthodes physiques — JTAG, UART, et SPI flash dump

La méthode physique la plus directe consiste à identifier et exploiter les interfaces de débogage laissées sur le PCB. La majorité des dispositifs IoT grand public expose encore ces interfaces, parfois avec des résistances de pull-down pour décourager l'accès sans pour autant les supprimer. L'UART (Universal Asynchronous Receiver-Transmitter) est la plus accessible : identifiez les 4 broches TX/RX/GND/VCC avec un multimètre en mode continuité, connectez-y un adaptateur USB-UART à 3.3V (jamais 5V — vous feriez frire le SoC), et vous avez accès à la console de boot. Beaucoup de firmwares affichent les credentials root ou ouvrent un shell sans authentification pendant la phase U-Boot.

Le SPI flash dump est encore plus direct sur les dispositifs avec flash NOR ou NAND externe (chips SOIC-8 ou SOIC-16). Avec un clip Pomona 5250 et flashrom :

# Connexion au flash SPI avec flashrom (adaptateur CH341A ou Bus Pirate)
# Identifier le chip (liste des chips supportés: flashrom.org/Supported_hardware)
flashrom -p ch341a_spi --flash-name

# Dump complet du flash SPI (ex: Winbond W25Q64 = 8MB)
flashrom -p ch341a_spi -r firmware_dump.bin
# Vérification par double lecture
flashrom -p ch341a_spi -r firmware_dump2.bin
md5sum firmware_dump.bin firmware_dump2.bin

# Connexion UART avec screen (détecter le baud rate avec baudrate.py ou essayer 115200)
screen /dev/ttyUSB0 115200
# Alternative avec minicom
minicom -D /dev/ttyUSB0 -b 115200

# Si le dispositif utilise JTAG, identifier les broches avec JTAGulator (bruteforce)
# puis utiliser OpenOCD pour accéder à la mémoire flash via JTAG
openocd -f interface/ftdi/jlink.cfg -f target/ar9331.cfg
# Dans la console OpenOCD:
# telnet localhost 4444
# > flash banks
# > dump_image flash_dump.bin 0x9f000000 0x800000

Méthodes logicielles — interception OTA et API fabricant

Si vous n'avez pas accès physique, ou si vous cherchez le firmware avant même d'acheter le dispositif, les méthodes logicielles sont souvent suffisantes. La mise à jour OTA (Over-The-Air) peut être interceptée avec mitmproxy : configurez le dispositif pour utiliser votre proxy en MITM, et capturez le binaire lors d'une mise à jour. Beaucoup de fabricants utilisent des connexions HTTP non chiffrées ou des TLS avec validation incorrecte du certificat. Autre approche : les API fabricant exposées sur le site officiel qui permettent de télécharger le firmware directement.

Analyse statique avec Binwalk : extraire et cartographier

Binwalk est l'outil d'entrée en matière pour tout reverse engineering firmware. Son moteur de détection basé sur des signatures identifie les systèmes de fichiers, les en-têtes d'archive, les clés de chiffrement, et les binaires embarqués dans un firmware brut en quelques secondes.

# Analyse basique : identifier les composants du firmware
binwalk firmware_dump.bin

# Extraction récursive (-e extract, -M recursive Matryoshka)
# Extrait chaque composant détecté, récursivement jusqu'au système de fichiers
binwalk -eM firmware_dump.bin

# Analyse d'entropie — identifier les zones chiffrées ou compressées
# Haute entropie (~8.0) = chiffré ou compressé | Basse entropie = données/code
binwalk -E firmware_dump.bin

# Analyse des strings dans tout le firmware
strings firmware_dump.bin | grep -iE "password|passwd|admin|secret|key|token|api"
strings firmware_dump.bin | grep -E "^[A-Za-z0-9+/]{20,}={0,2}$"  # Base64

# Après extraction — explorer le système de fichiers
ls -la _firmware_dump.bin.extracted/
# Structure typique routeur: squashfs-root/ avec bin/ etc/ usr/ var/

# Trouver les fichiers de configuration avec credentials
find _firmware_dump.bin.extracted/ -name "*.conf" -o -name "*.cfg" | xargs grep -l "password"
find _firmware_dump.bin.extracted/ -name "shadow" -o -name "passwd"
cat _firmware_dump.bin.extracted/etc/shadow

# Identifier les binaires ELF (architecture ARM ou MIPS)
find _firmware_dump.bin.extracted/ -type f | xargs file 2>/dev/null | grep ELF

# Scripts d'init — source d'informations sur les services démarrés
cat _firmware_dump.bin.extracted/etc/init.d/rcS
ls _firmware_dump.bin.extracted/etc/init.d/

Un résultat Binwalk typique sur un firmware de routeur domestique révèle : un loader U-Boot, une image kernel Linux compressée (zlib ou lzma), et un système de fichiers SquashFS ou JFFS2. Le système de fichiers SquashFS est votre cible principale — il contient tous les binaires et configurations du firmware.

OutilCas d'usage principalArchitectureForceLimite
BinwalkExtraction FS, analyse entropieToutesRapide, automatiséPas de décompilation
GhidraDécompilation, analyse de codeMIPS, ARM, x86, RISC-VDécompilateur intégré, scriptableCourbe d'apprentissage
Radare2Analyse bas niveau, scriptingToutesScriptable r2pipe, CLI puissantInterface peu intuitive
IDA FreeAnalyse statique, graphes de fluxx86/x64 uniquement (Free)Interface mature, pluginsVersion gratuite limitée
QEMUÉmulation complèteARM, MIPS, PowerPCExécution réelle du firmwareConfiguration complexe
FirmadyneÉmulation automatiséeMIPS, ARM (Linux)Pipeline automatiséLinux uniquement, RTOS non supporté

Décompilation avec Ghidra : trouver les fonctions critiques

Ghidra, développé et open-sourcé par la NSA, est devenu le standard de facto pour la décompilation de firmware. Son décompilateur génère du pseudo-code C lisible pour les architectures MIPS (routeurs) et ARM (caméras, IoT embarqué) — les deux architectures dominantes de l'écosystème IoT.

# Installation Ghidra (Java 17+ requis)
wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.1.2_build/ghidra_11.1.2_PUBLIC_20240709.zip
unzip ghidra_11.1.2_PUBLIC_20240709.zip
./ghidra_11.1.2_PUBLIC/ghidraRun

# En mode headless (batch analysis — utile pour plusieurs binaires)
./analyzeHeadless /tmp/ghidra_project MyProject -import /path/to/binary \
  -postScript FindAuthFunctions.py \
  -scriptPath /path/to/scripts/ \
  -deleteProject

# Import depuis Binwalk — tous les binaires ELF du firmware
for elf in $(find _firmware_dump.bin.extracted/ -type f | xargs file | grep ELF | cut -d: -f1); do
  echo "Importing: $elf"
  ./analyzeHeadless /tmp/ghidra_project FirmwareProject -import "$elf" -overwrite 2>/dev/null
done

Script Ghidra Python pour automatiser la recherche des fonctions d'authentification :

#!/usr/bin/env python3
# Script Ghidra Python (GhidraScript)
# Cherche les fonctions qui comparent des strings statiques (pattern auth)
# Sauvegarder dans ~/.ghidra/ghidra_scripts/FindAuthFunctions.py
# Lancer depuis: Ghidra > Script Manager > FindAuthFunctions.py

from ghidra.program.model.listing import Function
from ghidra.program.model.symbol import SymbolType
from ghidra.app.decompiler import DecompInterface, DecompileOptions
from ghidra.util.task import ConsoleTaskMonitor

# Fonctions de comparaison de strings à surveiller
AUTH_FUNCS = ['strcmp', 'strcasecmp', 'strncmp', 'strncasecmp', 'memcmp']

# Strings suspectes hardcodées (credentials typiques IoT)
SUSPECT_STRINGS = [
    'admin', 'password', 'passwd', '12345', 'default',
    'guest', 'root', 'support', 'supervisor', 'telnet',
    'debug', 'backdoor', 'factory', 'service'
]

def run():
    program = currentProgram
    func_manager = program.getFunctionManager()
    decompiler = DecompInterface()
    decompiler.openProgram(program)
    options = DecompileOptions()
    decompiler.setOptions(options)
    monitor = ConsoleTaskMonitor()

    results = []

    # Itérer sur toutes les fonctions
    for func in func_manager.getFunctions(True):
        decomp = decompiler.decompileFunction(func, 60, monitor)
        if not decomp.decompileCompleted():
            continue

        decompiled = decomp.getDecompiledFunction()
        if not decompiled:
            continue

        code = decompiled.getC()
        func_name = func.getName()

        # Chercher les appels aux fonctions de comparaison
        for auth_func in AUTH_FUNCS:
            if auth_func in code:
                # Chercher des strings statiques dans les arguments
                for suspect in SUSPECT_STRINGS:
                    if f'"{suspect}"' in code.lower() or f"'{suspect}'" in code.lower():
                        result = f"[AUTH] {func_name} @ {func.getEntryPoint()}: {auth_func}() avec string '{suspect}'"
                        results.append(result)
                        print(result)

    # Export des résultats
    output_path = "/tmp/ghidra_auth_findings.txt"
    with open(output_path, 'w') as f:
        f.write(f"=== Auth Function Analysis: {program.getName()} ===\n")
        f.write(f"Found {len(results)} suspicious patterns\n\n")
        for r in results:
            f.write(r + "\n")

    print(f"\n[+] {len(results)} patterns trouvés -> {output_path}")

run()

Analyse avec Radare2 : compléments ARM/MIPS et scripting r2pipe

Radare2 complète Ghidra sur des cas où le scripting en ligne de commande est plus efficace que l'interface graphique — notamment pour l'analyse en batch de dizaines de binaires, ou pour des architectures exotiques que Ghidra supporte moins bien. Son interface r2pipe permet de l'appeler depuis Python ou JavaScript.

# Analyse d'un binaire MIPS (router firmware)
# MIPS little-endian ou big-endian selon le chipset (Atheros = BE, MediaTek = LE)
r2 -a mips -b 32 -e cfg.bigendian=true ./httpd

# Analyse automatique et recherche des imports
aaa   # analyse complète (peut prendre du temps)
ii    # imports (fonctions externes appelées)
iz    # strings dans les sections data
izz   # strings dans tout le binaire (plus lent)

# Chercher les références à "password" ou "admin"
/ password
/ admin

# Afficher les fonctions qui réfèrent à ces strings
axt @@ hit0_*

# Désassembler une fonction spécifique
s sym.check_login  # aller à la fonction check_login
pdf              # print disassembly of function

# r2pipe depuis Python — analyser 50 binaires en batch
#!/usr/bin/env python3
# r2pipe — analyse en batch de binaires firmware IoT
# pip install r2pipe

import r2pipe
import os
import json

def analyze_binary(path: str) -> list:
    findings = []
    try:
        r2 = r2pipe.open(path, flags=['-2'])  # -2 = stderr to /dev/null
        r2.cmd('aaa')  # analyse complète

        # Chercher les strings suspectes
        strings = r2.cmdj('izzj') or []
        for s in strings:
            val = s.get('string', '')
            if any(kw in val.lower() for kw in ['password', 'admin', 'secret', 'key', 'token']):
                findings.append({
                    'binary': os.path.basename(path),
                    'type': 'suspect_string',
                    'value': val,
                    'offset': hex(s.get('vaddr', 0))
                })

        # Chercher les appels à des fonctions de crypto faible
        imports = r2.cmdj('iij') or []
        weak_crypto = ['MD5', 'MD5_Init', 'DES_', 'RC4', 'des_']
        for imp in imports:
            name = imp.get('name', '')
            if any(wc in name for wc in weak_crypto):
                findings.append({
                    'binary': os.path.basename(path),
                    'type': 'weak_crypto',
                    'function': name
                })

        r2.quit()
    except Exception as e:
        pass
    return findings

# Scanner tous les ELF du firmware extrait
firmware_dir = './_firmware_dump.bin.extracted'
all_findings = []

for root, _, files in os.walk(firmware_dir):
    for fname in files:
        fpath = os.path.join(root, fname)
        # Vérifier que c'est un ELF
        try:
            with open(fpath, 'rb') as f:
                if f.read(4) == b'\x7fELF':
                    findings = analyze_binary(fpath)
                    all_findings.extend(findings)
        except:
            pass

print(f"[+] {len(all_findings)} findings dans {firmware_dir}")
for f in all_findings[:20]:
    print(f"  [{f['type']}] {f['binary']}: {f.get('value', f.get('function', ''))}")

Émulation avec QEMU et Firmadyne : exécuter le firmware sans le matériel

L'émulation transforme l'analyse statique en dynamique — vous exécutez réellement le firmware, interrogez ses services réseau, et testez les vulnérabilités sans avoir le dispositif physique. Deux niveaux d'émulation sont disponibles : émulation en mode user (un seul processus) et émulation système complète.

# Prérequis: qemu-user-static, qemu-system-mips
apt install qemu-user-static qemu-system-mips binfmt-support

# Émulation user-mode MIPS — exécuter un binaire MIPS directement
# (pour les firmwares extraits avec Binwalk)
cp $(which qemu-mips-static) _firmware_dump.bin.extracted/squashfs-root/
chroot _firmware_dump.bin.extracted/squashfs-root/ /qemu-mips-static /bin/sh

# Depuis le chroot — tester les binaires directement
/usr/sbin/httpd -p 8080 &
wget -q -O- http://localhost:8080/

# Émulation système complète avec QEMU (routeur MIPS OpenWrt)
# Télécharger l'image QEMU OpenWrt
wget https://downloads.openwrt.org/releases/23.05.0/targets/malta/be/openwrt-23.05.0-malta-be-vmlinux.elf

qemu-system-mips \
  -kernel openwrt-23.05.0-malta-be-vmlinux.elf \
  -drive file=firmware.img,format=raw \
  -append "root=/dev/sda console=tty0" \
  -net nic -net tap,ifname=tap0,script=no \
  -nographic

# Firmadyne — émulation automatisée de firmwares Linux IoT
# Installation (Ubuntu 22.04 recommandé)
git clone --recursive https://github.com/firmadyne/firmadyne.git
cd firmadyne
./download.sh  # télécharge les dépendances

# Pipeline Firmadyne en 4 étapes
# 1. Extraction et identification du firmware
python3 sources/extractor/extractor.py -b Netgear -sql 127.0.0.1 \
  -np -nk firmware_netgear.bin images/

# 2. Identification de l'architecture
./scripts/getArch.sh ./images/1.tar.gz

# 3. Création du système de fichiers
sudo python3 ./scripts/makeImage.sh 1

# 4. Inférence de la configuration réseau et lancement
./scripts/inferNetwork.sh 1
sudo ./scratch/1/run.sh  # démarre l'émulation

# Tester les services exposés
nmap -sV 192.168.0.1  # IP attribuée par Firmadyne
curl http://192.168.0.1/  # interface web du firmware

Comment trouver les secrets hardcodés : credentials, clés et certificats embarqués ?

Parmi toutes les vulnérabilités qu'on trouve dans les firmwares IoT, les credentials hardcodés et les clés privées embarquées sont les plus fréquentes et les plus exploitables. Une clé SSH privée dans un firmware = accès root immédiat à tous les dispositifs du même modèle dans le monde.

# Recherche de credentials en clair dans le système de fichiers extrait
cd _firmware_dump.bin.extracted/

# Passwords dans les fichiers shadow et passwd
find . -name "shadow" -o -name "passwd" | xargs grep -v "^#" | grep -v ":\*:" | grep -v ":!:"

# Strings dans tous les binaires — patterns credentials
find . -type f | xargs strings 2>/dev/null | \
  grep -iE "(password|passwd|secret|apikey|api_key|token)" | \
  grep -v "^#" | sort -u

# Recherche de clés SSH privées
grep -r "BEGIN.*PRIVATE KEY" . 2>/dev/null
grep -r "BEGIN RSA PRIVATE KEY" . 2>/dev/null
find . -name "*.pem" -o -name "*.key" -o -name "id_rsa" 2>/dev/null

# Certificats TLS — vérifier si la clé privée est embarquée avec le cert
find . -name "*.crt" -o -name "*.cert" | head -20
# Si cert + key sont dans le même répertoire = vulnérabilité critique

# TruffleHog pour la détection de secrets (approche plus fine)
pip install trufflehog
trufflehog filesystem _firmware_dump.bin.extracted/ --json 2>/dev/null | \
  python3 -c "import sys,json; [print(json.dumps(json.loads(l), indent=2)) for l in sys.stdin]"

# Analyse d'entropie ciblée pour détecter les clés de chiffrement AES/RSA
# (entropie élevée sur une zone de taille 16, 32, 128, 256 bytes = clé probable)
python3 -c "
import math, os, sys

def entropy(data):
    if not data: return 0
    freq = {}
    for b in data:
        freq[b] = freq.get(b, 0) + 1
    return -sum((c/len(data)) * math.log2(c/len(data)) for c in freq.values())

# Scanner les fichiers binaires pour des zones de haute entropie
for root, _, files in os.walk('_firmware_dump.bin.extracted'):
    for fname in files:
        fpath = os.path.join(root, fname)
        try:
            with open(fpath, 'rb') as f:
                data = f.read()
            # Fenêtre glissante de 32 bytes
            for i in range(0, len(data)-32, 16):
                chunk = data[i:i+32]
                e = entropy(chunk)
                if e > 7.8:  # Seuil = potentiellement une clé
                    print(f'{fpath}@{hex(i)}: entropie={e:.2f} -> {chunk[:16].hex()}')
        except: pass
" 2>/dev/null | head -50

CVE IoT réels : vulnérabilités trouvées par reverse engineering

Le reverse engineering firmware a conduit à la découverte de centaines de CVE critiques ces dernières années. Quelques exemples représentatifs de la méthodologie :

Credentials hardcodés systémiques (pattern récurrent) : De nombreux fabricants de routeurs entrée de gamme embarquent des comptes de maintenance avec des mots de passe identiques sur toute une gamme de produits. La méthode de découverte est systématiquement la même : extraction Binwalk + dump du fichier /etc/shadow dans le SquashFS. Les hashs des comptes de maintenance sont souvent des hashs MD5 faibles crackables en quelques minutes avec john ou hashcat. CVE-2021-1497 (Cisco HyperFlex HX) ou CVE-2022-20700 (Cisco Unified Communications Manager) illustrent cette classe de vulnérabilités à grande échelle.

Backdoor d'accès UART/Telnet non documentées : l'analyse des scripts d'initialisation dans /etc/init.d/ révèle fréquemment des services Telnet ou FTP démarrés par défaut sans documentation dans la notice utilisateur. Ces services utilisent des credentials identiques à ceux trouvés dans le fichier shadow. CVE-2020-8958 (Guangzhou 1GE ONU V2804RGW) en est un exemple documenté.

Clés TLS privées partagées entre modèles : en 2015, l'analyse de firmware de dizaines de dispositifs Cisco, Juniper, ZTE, et d'autres fabricants a révélé que des milliers de dispositifs différents partageaient les mêmes clés privées TLS et SSH — extraites depuis les firmwares par la recherche en sécurité (projet "House of Keys" de SEC Consult). Chaque firmware extrait avec Binwalk exposait directement la clé privée en clair dans le système de fichiers.

Format des déclarations CVE pour les chercheurs : une découverte par RE firmware doit être déclarée avec le CVSS v3.1 score, la version du firmware affectée (récupérable depuis le binaire ou la page produit), et la preuve de concept minimale permettant la reproduction. L'ENISA fournit un guide de sécurité IoT et le NIST SP 800-213 définit les critères de sécurité recommandés pour les dispositifs IoT qui guident l'évaluation des découvertes.

Exemple concret : analyse d'un routeur domestique avec QEMU

Voici un workflow complet sur un routeur domestique générique à base de Mediatek MT7621 (architecture MIPS little-endian), disponible à moins de 30€ sur le marché — représentatif de dizaines de millions de dispositifs déployés dans des foyers et des PME françaises.

# Étape 1 — Extraction du firmware
# Méthode 1 : téléchargement direct depuis le site fabricant
wget https://fabricant.com/support/firmware/routeur-v3.2.1.bin -O firmware.bin

# Méthode 2 : interception OTA avec mitmproxy
mitmproxy --mode transparent --ssl-insecure -p 8080 &
# Configurer le routeur pour utiliser le proxy, puis déclencher une mise à jour

# Étape 2 — Analyse Binwalk
binwalk -eM firmware.bin
# Résultat typique:
# 0x00000000  TRX firmware header, little endian
# 0x0001C000  LZMA compressed data (kernel)
# 0x00160000  Squashfs filesystem (little endian, 4.0)

cd _firmware.bin.extracted/

# Étape 3 — Analyse rapide des vulnérabilités évidentes
cat squashfs-root/etc/shadow | head -5
# Exemple de sortie vulnérable:
# root:$1$abc123$XXXXXXXXXXXXXXXXXXXXXXXX:0:0:99999:7:::
# admin:$1$abc123$YYYYYYYYYYYYYYYYYYYYYYYY:0:0:99999:7:::
# Note: $1$ = MD5 — crackable en quelques minutes

# Crack du hash MD5 avec John
echo 'root:$1$abc123$XXXXXXXXXXXXXXXXXXXXXXXX:' > hash.txt
john --format=md5crypt-opencl hash.txt --wordlist=/usr/share/wordlists/rockyou.txt

# Étape 4 — Audit des services réseau
cat squashfs-root/etc/init.d/rcS | grep -E "telnet|ftp|ssh|httpd"
cat squashfs-root/etc/services

# Étape 5 — Émulation et test dynamique
# Setup réseau tap
sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 up
sudo ip addr add 192.168.100.1/24 dev tap0

# Émulation MIPS LE (Mediatek)
qemu-system-mipsel \
  -M malta \
  -kernel ./vmlinux-5.10.0-mipsel \
  -append "root=/dev/sda console=ttyS0 nokaslr" \
  -hda ./firmware_rootfs.img \
  -netdev tap,id=net0,ifname=tap0,script=no \
  -device pcnet,netdev=net0 \
  -nographic

# Depuis l'hôte — tester l'interface web
curl -s http://192.168.100.2/ | grep -i "login\|auth\|password"

# Test des endpoints API (si interface REST détectée)
curl -s http://192.168.100.2/api/v1/device/info
curl -s -X POST http://192.168.100.2/login \
  -d "username=admin&password=admin" -L

Cadre légal obligatoire : Les techniques présentées dans cet article sont destinées à être appliquées uniquement sur des dispositifs que vous possédez personnellement, dans le cadre de votre propre réseau domestique ou de laboratoire isolé, ou dans le cadre d'un engagement de pentest/bug bounty avec autorisation écrite explicite du propriétaire du dispositif. Le reverse engineering non autorisé de dispositifs tiers est sanctionné pénalement en France par les articles 323-1 à 323-7 du Code pénal. La découverte de vulnérabilités dans des firmwares doit faire l'objet d'une divulgation coordonnée (CVD) en contactant le fabricant et le CERT-FR avant toute publication.

Divulgation responsable : comment signaler une vulnérabilité IoT ?

La découverte d'une vulnérabilité firmware engage une responsabilité éthique et légale. Le processus de divulgation coordonnée (Coordinated Vulnerability Disclosure) protège à la fois le chercheur et les utilisateurs.

Protocole standard en 4 étapes :

  1. Notification privée au fabricant : rapport détaillé avec description de la vulnérabilité, étapes de reproduction, impact potentiel (CVSS score), et proof of concept. Envoyez à [email protected] ou utilisez le contact PSIRT si disponible
  2. Accusé de réception : le fabricant dispose de 7 jours pour accuser réception et 90 jours pour corriger — standard industriel CERT/CC et Google Project Zero
  3. Escalade CERT-FR si nécessaire : si le fabricant ne répond pas ou refuse de corriger, le CERT-FR peut intervenir comme médiateur. Pour les fabricants hors Union Européenne, l'ENISA peut coordonner
  4. Publication responsable : publiez la vulnérabilité avec le correctif ou à l'expiration du délai de 90 jours, en notifiant les utilisateurs via les canaux industriels appropriés

Un programme de bug bounty actif chez le fabricant simplifie considérablement ce processus — certains fabricants (Netgear, TP-Link, Synology) ont mis en place des programmes via Bugcrowd ou HackerOne avec des récompenses allant de 500$ à 30 000$ selon la criticité.

Questions fréquentes

Binwalk ne détecte rien — le firmware est-il chiffré ?

Une entropie uniforme proche de 8.0 sur l'ensemble du firmware indique un chiffrement (AES, ChaCha20) ou une compression sans signature reconnue. Dans ce cas, cherchez la clé dans d'autres sources : la version précédente du firmware (non chiffrée), les binaires du bootloader U-Boot qui contient souvent la routine de déchiffrement, ou les communications du dispositif en UART durant le boot. La commande binwalk -E firmware.bin génère un graphe d'entropie — une courbe plate proche de 8.0 confirme le chiffrement.

Comment identifier l'architecture CPU d'un firmware inconnu ?

Utilisez la commande file firmware_binary sur les binaires ELF extraits — elle indique l'architecture (MIPS, ARM, PowerPC) et l'endianness. Pour les firmwares bruts sans en-tête ELF reconnu, binwalk --disasm firmware.bin tente une détection de code machine. La référence du SoC sur le PCB (Mediatek MT7621, Qualcomm IPQ4018, Realtek RTL8197F) indique systématiquement l'architecture dans les datasheets fabricant.

Peut-on analyser un firmware RTOS (FreeRTOS, VxWorks) avec les mêmes outils ?

Partiellement. Binwalk détecte les images FreeRTOS et VxWorks via des signatures d'en-tête. Ghidra supporte ces architectures en décompilation. L'émulation est en revanche plus difficile — Firmadyne ne supporte que Linux, et les RTOS propriétaires comme VxWorks nécessitent des émulateurs spécialisés (Avatar², HALucinator) ou une émulation partielle via QEMU en mode user avec les bibliothèques du RTOS. Les outils OSINT permettent parfois d'identifier la version VxWorks depuis les strings dans le firmware.

Ghidra ou IDA Pro pour le firmware IoT ?

Pour le firmware IoT (ARM/MIPS), Ghidra est à privilégier dans 90% des cas : il est gratuit, supporte nativement ces architectures, dispose d'un décompilateur de qualité comparable à IDA Pro, et son scripting Python est plus accessible. IDA Pro garde un avantage sur les analyses très complexes (obfuscation avancée, symboles partiels) et dans les environnements professionnels où le support commercial est requis. La version IDA Free est limitée à x86/x64 — inutile pour MIPS ou ARM.

Comment automatiser l'analyse de masse sur 100+ firmwares ?

Le pipeline recommandé pour l'analyse en masse : Binwalk en batch avec binwalk -eM --run-as=root sur un répertoire de firmwares, suivi de Ghidra headless mode avec un script Python qui recherche les patterns d'authentification, complété par un scan de strings automatisé et TruffleHog pour les secrets. Firmadyne peut automatiser l'émulation sur plusieurs dizaines de firmwares en parallèle. L'IA générative commence également à s'imposer pour l'analyse sémantique du pseudo-code décompilé — des outils comme GPT-4 ou des modèles spécialisés peuvent identifier des patterns d'authentification incorrects depuis le pseudo-C Ghidra.

Conclusion

Le reverse engineering firmware IoT est une discipline qui demande de la méthode plus que du génie. Un Binwalk bien lancé révèle en 30 secondes ce que des années de tests boîte noire ne trouveraient pas. Un script Ghidra bien écrit remplace des semaines d'analyse manuelle. L'enjeu n'est pas technique — il est d'échelle : des milliards de dispositifs IoT déployés, la plupart jamais audités, la plupart avec des credentials identiques sur toute leur génération. Chaque firmware audité et divulgué responsablement réduit cette surface d'attaque pour tous les utilisateurs. La sécurité IoT n'avancera que si la communauté de recherche continue à exercer cette pression sur les fabricants — légalement, méthodiquement, et avec rigueur dans la divulgation.

Vous gérez un parc de dispositifs IoT industriels ou souhaitez auditer la sécurité de vos équipements réseau ? Notre équipe réalise des audits de firmware IoT avec rapport de vulnérabilités et recommandations de remédiation. Contactez-nous pour un devis d'audit firmware.