La vérification qu'une plateforme PC est correctement configurée pour limiter l'exposition de celle-ci est fastidieuse et complexe si elle est effectuée manuellement. L'outil Chipsec permet de faciliter grandement ces opérations, tant par son support des différents modes d'accès que par celui des différentes plateformes. Cet article présente son fonctionnement interne et son utilisation à des fins de tests de conformité.
1. Contexte
Depuis quelques années, l’ANSSI est impliquée dans les procédures d’acquisition des matériels bureautiques pour l’administration française, afin de compléter les exigences fonctionnelles (taille, performances, etc.) par des exigences de sécurité. Ces exigences, publiées [1] sur le site de l’ANSSI, permettent de renforcer le niveau de sécurité des plateformes (postes clients et portables) et sont regroupées en plusieurs familles :
- maîtrise de la plateforme : pour s’assurer que les postes acquis sont sous le contrôle de l’administration ;
- caractéristiques matérielles : pour s’assurer que des dispositifs matériels bénéfiques à la sécurité (I/OMMU, TPM, etc.) soient présents ;
- caractéristiques du firmware : fonctionnalités de sécurité offertes par le firmware UEFI (ou BIOS), possibilités de configurations et protection du firmware lui-même ;
- maintien en condition de sécurité : pour s’assurer que le niveau de sécurité reste satisfaisant dans le temps.
La troisième famille comporte un certain nombre d’exigences sur la protection logicielle de la plateforme, en particulier eu égard aux vulnérabilités identifiées ces dernières années au niveau des BIOS. Dans la plupart des cas, ces vulnérabilités étaient liées à une mauvaise configuration de la plateforme au démarrage, dans d’autres cas, il s’agissait de vulnérabilités intrinsèques à l’architecture Intel, corrigées par l’ajout de fonctionnalités à activer.
Dans les deux cas, la prise en compte de ces vulnérabilités se fait via la configuration de la plateforme au démarrage, ce qui est habituellement du ressort du développeur du BIOS et du fournisseur de la machine. La vérification de la bonne configuration d’une plateforme peut se faire manuellement à l’aide de la documentation (processeurs et chipsets Intel en particulier) et d’outils tels que pcilib (lspci, setpci). Ce mode manuel est présenté dans l’article Relevé de configuration matérielle sur plateforme x86 dans ce même numéro de MISC, sa lecture est recommandée avant de lire celui-ci.
La taille et la complexité de la documentation, les dépendances nombreuses entre registres de configuration et les différents modes d’accès aux registres rendent cette vérification très fastidieuse, aussi nous avons décidé de nous reposer sur l’outil Chipsec pour valider la configuration des plateformes acquises par l’administration.
2. Pourquoi utiliser Chipsec ?
Chipsec [2] est un framework Python open source (publié en mars 2014) dédié à l’analyse du niveau de sécurité des plateformes Intel x86 en vérifiant les mécanismes de sécurité bas niveau, les paramètres de configuration de composants matériels ou encore des micrologiciels (BIOS/UEFI). Chipsec peut être lancé depuis un système d’exploitation (Windows, Linux, macOS) ou un shell UEFI.
Chipsec est composé de deux scripts principaux : chipsec_main.py et chipsec_util.py.
Le premier a été conçu pour détecter automatiquement les mauvaises sécurisations à travers une série de modules (ou plugins). Chacun de ces derniers a une fonction précise et cherche à détecter une configuration permettant l’exploitation d’une vulnérabilité spécifique. Chacune des vulnérabilités testées a généralement fait l’objet d’une publication et elles ont une finalité commune : exécuter du code malveillant sur le système d’exploitation depuis un accès plus bas niveau (par exemple, en modifiant le code du BIOS, en exécutant du code malveillant en mode SMM, ou en exploitant des options CPU mal documentées).
L’exécution de chipsec_main renvoie un rapport de résultats qui doit être analysé attentivement afin de valider que tous les résultats sont conformes (une seule non-conformité peut mener à la compromission de la plateforme).
En cas d’échec, l’analyste peut se reposer sur la sortie des différents modules pour comprendre la raison de la non-conformité.
Ce mode est celui principalement utilisé pour la validation des configurations.
Le second script, chipsec_util, est davantage utilisé pour réaliser des opérations manuelles en communiquant de manière ciblée avec un matériel.
Dans le cadre des évaluations ANSSI, pour comprendre le résultat d’un plugin ou pour extraire une donnée non prise en charge par l’un des plugins ou encore pour extraire le firmware, cet outil s’est avéré très précieux, le nombre de protocoles et de moyens d’accès aux registres de configuration pris en charge étant assez important. Il existe ainsi des modules PCI, MMIO, SPI, UEFI, TPM, IOMMU, etc.
3. Détection de plateformes vulnérables via Chipsec
Nous n’allons pas présenter ici la totalité des vulnérabilités testées par Chipsec, mais présenter quelques modules adossés à des vulnérabilités ayant eu un certain retentissement médiatique dans la communauté et un impact important sur la sécurité de la plateforme. Un document complet détaillant les tests menés par Chipsec est toutefois présent sur le GitHub de l’ANSSI [3] et indique également le protocole de test permettant de valider la conformité d’une plateforme soumise.
3.1 Détection des vulnérabilités propres à la Flash SPI via les modules bios_wp et bios_smi
Un registre très important est celui protégeant en écriture des régions de la flash SPI une fois le système démarré : BIOS_CNTL (Bios Control Register, maintenant appelé BC) du PCH. Contenant 3 bits d’une importance cruciale pour protéger le firmware des altérations, il est probablement le registre le plus exploité par les vulnérabilités découvertes jusqu’à maintenant.
Chipsec vérifie notamment ces valeurs à travers le module bios_wp en vérifiant les bits :
- BIOSWE : BIOS Write Enable, si ce bit est à 1, un accès à la flash SPI en écriture sera possible depuis le système d’exploitation (avec les privilèges du ring 0) ;
- BLE : BIOS Lock Enable
- si ce bit est à 1, à chaque tentative de modification du bit BIOSWE, une interruption SMI générée par le PCH empêchera tout simplement l’opération ;
- par contre, si ce bit vaut 0 alors, depuis l’espace noyau, il sera possible de modifier le bit BIOSWE pour déverrouiller la flash SPI et donc altérer son contenu.
Cependant, cette protection SMI a déjà pu être contournée à plusieurs reprises notamment à travers l’attaque SpeedRacer [4]. Celle-ci consiste à être plus rapide que le contrôle SMI en jouant avec plusieurs cœurs du processeur afin d’écrire dans la région du BIOS avant le déclenchement de l’interruption et l’entrée en SMM.
Une autre attaque nommée Sandman [5] consiste quant à elle à désactiver complètement les SMI sur le système pour empêcher le contrôle en mode SMM et permettre la modification de BIOSWE. Cette désactivation des sources SMI se fait en passant le bit GBL_SMI_EN (du registre SMI_EN) à 0. Ce registre est lui-même verrouillé par le bit SMI_LOCK (du registre GEN_PMCON_1) positionné à 0. Cette attaque a été utilisée en pratique pour contourner Secure Boot [6].
Chipsec vérifie ces deux bits via le module bios_smi.
Une protection supplémentaire repose sur le bit SMM_BWP (SMM BIOS Write Protect Disable) du registre BIOS_CNTL, qui permet de protéger le BIOS d’une telle attaque en protégeant sa modification même si le contrôle SMI n’est pas configuré ou échoue. Si ce bit est à 1, la région SPI propre au BIOS ne pourra être modifiée que si le processeur s’exécute en mode SMM et donc que le code provient du BIOS. Ce mécanisme est typiquement utilisé lors d’une mise à jour du BIOS pour réécrire le contenu de la mémoire flash avec le nouveau BIOS.
Alors que les attaques présentées jusque-là ne nécessitaient qu’un accès au noyau (par un pilote par exemple), il est nécessaire, avec cette protection en place, d’exécuter du code en espace SMM pour altérer le BIOS, compliquant ainsi les exploitations. L’accès à un tel espace nécessite d’une part une élévation de privilèges à partir de l’espace noyau et d’autre part une porte dérobée SMM [7].
3.2 Détection des vulnérabilités S3 Resume via le module uefi.s3bootscript
En 2015, des chercheurs sont parvenus à infecter un firmware UEFI depuis le mode kernel alors que la flash SPI était correctement protégée par les bits de protection proposés par le registre BIOS_CNTL [8][9]. Deux vulnérabilités découvertes par les chercheurs et propres au mode de démarrage ACPI S3 Resume (sortie de veille de la plateforme) sont exploitées dans leur scénario.
Durant la phase de boot normal et notamment la phase DXE (chargement des drivers EFI) l’état du CPU et du chipset (comprenant donc les registres du PCH tels que BIOS_CNTL), est sauvegardé en mémoire dans une structure appelée UEFI boot script table. Cette table est ensuite utilisée lors de la phase de sortie de mise en veille (S3 resume) afin de réinitialiser plus rapidement l’état de la plateforme, en évitant notamment de devoir recharger tous les drivers EFI.
La première vulnérabilité exploite le fait que la sauvegarde de la table est réalisée durant la phase de boot avant que les registres aient été complètement verrouillés par le firmware EFI. Ainsi, au réveil de la plateforme plusieurs registres (dont BIOS_CNTL) ont un état déverrouillé et des valeurs telles que BIOSWP et SMM_BWP modifiables depuis un accès noyau. L’altération du firmware EFI devient alors possible après avoir reparamétré les valeurs du registre. Des mesures de sécurité ont depuis été poussées par Intel en recommandant par exemple d’effectuer la sauvegarde de l’état du CPU et du chipset après la demande de mise en veille S3 suspend et donc lorsque les registres sont correctement verrouillés.
Chipsec vérifie notamment si la plateforme testée est vulnérable via le module s3bootscript et le module tools.uefi.s3script_modify aide également à effectuer des tests concrets de modification des scripts.
Pour renforcer davantage la sécurité de la flash SPI, cinq nouveaux registres supplémentaires du contrôleur SPI, PRx (Protected Range), spécifiques à chaque région de la flash SPI, ont vu le jour pour définir les droits d’écriture (WP) et lecture (RP) sur chacune d’elles et ainsi empêcher toute altération de la cible prioritaire, le contenu de la flash SPI. Cette protection, dont le code fonctionne indépendamment du mode SMM, empêche l’écriture des régions de la flash via un code malveillant s’exécutant en mode SMM.
La vérification de ces registres est effectuée par le module Chipsec bios_wp (vu au paragraphe précédent).
4. Extraction des registres avec Chipsec
Comme vu dans l’article Relevé de configuration matérielle sur plateforme x86, la récupération d’informations dans les registres de configuration peut se faire de différentes façons suivant le type de bus et de périphérique (processeur, périphérique PCI, etc.). La localisation des informations (quel périphérique est concerné, quel registre sur ce périphérique, et où il se situe) est aussi complexe, la documentation (Intel en particulier) étant complexe et évoluant au fil du temps.
Chipsec fournit une abstraction logicielle permettant à l’analyste de se concentrer sur les éléments importants. Les deux scripts (chipsec_main fournissant le rapport complet, et chipsec_util permettant les interrogations ciblées) reposent sur un ensemble de fonctions fournissant à la fois les accès matériels et la vision cohérente de la plateforme à l’aide de fichiers de configuration fournis avec Chipsec.
4.1 Vérification du support de la plateforme
À chaque lancement de Chipsec, la fonction detect_platform de chipsec/chipset.py identifie les vendor ID et product ID du contrôleur de la RAM (00:0.0) et du chipset ou PCH (00:1F.0) via des requêtes PCI pour en déduire le modèle de la plateforme et s’assurer ainsi que Chipsec sera pris en charge.
L’extrait de code ci-dessous indique que le fichier de configuration à utiliser sera cfg/HSW.XML pour la plateforme Desktop 4th Generation Core Processor (Haswell CPU / Lynx Point PCH).
Déclaration du support d’une plateforme dans chipsec/chipset.py.
La base de traduction des identifiants VID:DID en nom de plateforme est fournie avec Chipsec, mais la source est identique à celle de pcilib et provient du dépôt GitHub PCIIDS [10].
Si la plateforme n’est pas connue de Chipsec alors l’opération échoue et Chipsec doit alors être adapté via les fichiers de configuration disponibles.
4.2 Spécifications des plateformes
Une force de Chipsec est que la présence des fichiers de configuration propres à un modèle de chipset de carte mère (chipsec/cfg/common.xml et chipsec/cfg/TAG.xml) remplace utilement les spécifications fournies par exemple par Intel. Cette configuration, issue des spécifications Intel et maintenue par les développeurs Chipsec (eux-mêmes développeurs chez Intel) spécifie les adresses des registres, leur mode d’accès ainsi que leur sémantique. Grâce à cette base de données, il n’est plus nécessaire de calculer ou de vérifier manuellement les paramètres comme effectué précédemment via setpci et le gain de temps est donc considérable.
Adresses PCI des composants du PCH.
Emplacement et taille des variables du registre BIOS_CNTL du PCH.
Adresse PCI et registre stockant l’adresse mémoire SPIBAR.
Emplacement mémoire du registre HSFS du contrôleur SPI et de ses variables.
4.3 Des modules au pilote chipsec.ko
4.3.1 Utilisation des fichiers de configuration
Depuis les modules Python (chipsec/modules/MODULE.py), les différents registres peuvent être extraits via des fonctions (déclarées dans chipsec/chipset.py) telles que read_register, get_control ou get_register_field.
Exemple du module bios_wp.py.
Exemple du module spi_fdopss.py.
Les controls sont des abstractions propres à Chipsec qui permettent d’exprimer des informations de haut niveau (par exemple, le verrouillage en écriture de la zone de la flash contenant le BIOS) qui peuvent reposer sur différents registres suivant les plateformes. Ces controls sont définis dans les fichiers de configuration XML de chaque plateforme et indiquent les registres et champs à consulter pour cette plateforme. Par exemple, le control SMILock est défini différemment selon la plateforme :
Dans le cas général :
Sur les PCH Intel Series 300 :
Les fonctions proposées pour la lecture des registres sont toutes disponibles dans chipsec/chipset.py.
Extrait des fonctions proposées par chipsec/chipset.py.
La suite des opérations sera différente selon le moyen d’accès utilisé pour accéder au registre (par exemple, PCI ou MMIO). Cette spécificité a été traduite dans le fichier de configuration XML par le champ type lors de la déclaration du registre (voir illustration plus haut).
Registre BC accessible via PCI (pcicfg).
Les différentes valeurs de ce champ sont notamment déclarées dans chipsec/chipset.py :
Les moyens d’accès aux registres supportés.
Ainsi, le développement de nouveaux plugins est très simplifié et c’est donc la configuration chargée qui définira la suite des opérations à lancer : requêtes PCI, MMIO etc. via des fonctions spécifiques telles que pci.read_* (de chipsec/hal/pci.py) pour des accès aux registres en PCI ou mmio.read_* (de chipsec/hal/mmio.py) pour les accès au registre en MMIO.
Extrait de read_register de chipsec/chipset.py.
4.3.2 Pour des accès PCI
Le module principal réalisant les requêtes PCI est situé dans le fichier chipsec/hal/pci.py et comprend différentes fonctions prenant en argument une adresse PCI (B:D.F) et un offset représentant le début d’un registre (de 8, 16 ou 32 bits) : read_byte, read_word, read_dword. Chacune de ces fonctions fait ensuite appel à la fonction read_pci_reg(bus, device, function, address, size) (disponible dans chipsec/helper/linux/linuxhelper.py).
Appel système ioctl pour un accès PCI.
Cette fonction prépare les données à transmettre au module (B:D.F et size) dans un buffer, et initie ensuite un appel système ioctl. Sous Linux, l’appel système ioctl permet d’échanger des données avec le noyau au travers d’un pseudo-fichier. Le prototype de l’appel ioctl(2) est :
Le fd (file descriptor) pointe vers un pseudo-fichier créé par un driver noyau, tandis que request est un code spécifique identifiant la requête et que le troisième argument est un pointeur vers un buffer contenant les arguments. Les codes de requête font partie de l’interface entre le code python et le code noyau, par exemple 0x3 pour READ_PCI.
Codes IOCTL disponibles (nr).
Les fichiers chipsec/helper/linux/linuxhelper.py et chipsec/drivers/linux/include/chipsec.h définissent clairement les structures et les autres paramètres utilisés :
Définition de _IOWR.
Définition de IOCTL_RDPCI.
4.3.3 Pour des accès MMIO
En ce qui concerne les accès MMIO, le module principal est chipsec/hal/mmio.py et propose des fonctions prenant en paramètre une adresse mémoire et un offset représentant le début d’un registre (8, 16, 32 bits ou défini par l’utilisateur) : read_MMIO_reg_byte, read_MMIO_reg_word, read_MMIO_reg_dword, read_MMIO_reg. Une autre fonction, read_MMIO_BAR_reg, prend en paramètre un nom d’espace mémoire BAR et permet de réaliser la lecture d’un registre en se basant simplement sur le nom déclaré dans la configuration XML.
SPIBAR déclaré dans le fichier de configuration XML.
Chacune de ces fonctions fait ensuite appel à read_mmio_reg(self, phys_address, size) disponible dans chipsec/helper/linux/linuxhelper.py pour initier un appel système ioctl, de façon identique aux accès PCI (le code de requête pour RDMMIO vaut 0x12).
Appel système ioctl pour un accès MMIO.
Un exemple de trace d’exécution de chipsec_main via strace montre l’utilisation d’un ioctl pour un accès PCI suivi d’un ioctl pour un accès MMIO.
Une option intéressante de chipsec_main est --hal qui permet d’afficher les informations d’accès MMIO, PCI et CPU ainsi que les valeurs extraites.
4.3.4 Module noyau
Comme évoqué précédemment, la lecture ou l’écriture de registres matériels nécessitent des permissions élevées sur un système. L’accès à l’espace des ports ou à l’espace mémoire physique nécessite au moins les permissions du super-utilisateur (typiquement root sous un système Unix). Sur des systèmes récents et avec un niveau de sécurité à l’état de l’art, même ces permissions ne sont parfois pas suffisantes.
L’accès complet à la mémoire physique (exposé sous Linux au travers du pseudo-fichier en mode caractère /dev/mem) est ainsi restreint à des zones particulières : sur architecture x86, uniquement le 1er Mo de mémoire physique ainsi que les zones PCI MMIO sont accessibles depuis le noyau 2.6.27, au travers de l’option CONFIG_STRICT_DEVMEM, habituellement activée sur les distributions standards.
Sur des noyaux plus récents (5.4 upstream, mais depuis plus longtemps sur des distributions comme Debian, Red Hat ou Ubuntu), la présence de la fonctionnalité Lockdown en présence de SecureBoot, interdit complètement l’accès à /dev/mem ainsi qu’à l’espace de configuration des ports.
Il n’est donc pas aisé sur une distribution standard d’accéder aux informations nécessaires, aussi Chipsec vient avec un driver noyau pour les différents systèmes d’exploitation. C’est ce driver noyau (drivers/linux/chipsec.ko), chargé au démarrage de Chipsec (par chipsec/helper/linux/linuxhelper.py), qui effectue les accès matériels, au service du code Python. L’interface entre les deux passe par un nœud de périphérique, un pseudo-fichier en mode caractère /dev/chipsec, sur lequel le code en espace utilisateur effectue des ioctl, comme vu aux paragraphes précédents.
4.4 Lister les contrôleurs périphériques PCI
Comme indiqué plus haut, le code dans chipsec/hal/pci.py est en charge de l’énumération des périphériques PCI, que ce soit de manière automatisée via chipsec_main ou avec l’option pci enumerate de chipsec_util.
L’énumération se fait de façon extensive en examinant, pour tous les bus (de 0 à 255), device (de 0 à 31) et function (de 0 à 7) le contenu des 8 premiers octets du PCI Configuration Space, qui correspondent au Vendor ID et Product ID du périphérique concerné (ou 0xFFFF/0XFFFF en cas d’absence ou de masquage du périphérique).
4.5 Extraire les valeurs des registres d’un périphérique PCI
À travers ses plugins et ses configurations XML, chipsec_main réalise automatiquement l’extraction des registres spécifiques. Par exemple, le plugin bios_wp récupère le contenu du registre BIOS_CNTL dans le PCH et ses valeurs telles que BIOSWE, BLE, etc. en indiquant si celles-ci sont conformes d’un point de vue sécurité.
La même opération peut être effectuée manuellement, sans se baser sur les fichiers de configuration, à l’aide de chipsec_util en spécifiant l’adresse du périphérique.
On peut ainsi effectuer un dump complet du PCI Configuration Space (similaire à lspci -xxx) :
ou encore demander explicitement le contenu du registre à l’aide de son adresse (de façon similaire à setpci) :
4.6 Accès MMIO
Chipsec dispose d’un module permettant les accès à des registres projetés en mémoire (MMIO). Ce module peut être utilisé directement pour lire des adresses arbitraires en mémoire, mais il est particulièrement utile pour récupérer des informations de configuration de périphériques pour lesquels celles-ci sont projetées en mémoire à des adresses précises, avec parfois plusieurs niveaux d’indirection, comme par exemple le contrôleur SPI vu dans l’article sur le relevé de configuration.
Tous les modules chipsec commençant par spi_ ont ainsi besoin d’accéder au contrôleur SPI via une zone mémoire projetée à l’adresse SPIBAR (SPI Base Address).
Tous les éléments nécessaires au calcul de cette adresse mémoire (emplacement du registre RCRA indiquant l’adresse du RCRB, constante à ajouter) sont stockés dans les fichiers de configuration XML et facilitent l’automatisation. Une requête PCI vers le PCH et un calcul suffisent ainsi à l’identification de l’adresse mémoire SPIBAR (0xFED1F800).
Il est possible là encore de trouver manuellement l’adresse de SPIBAR, en effectuant à la main les différentes requêtes via chipsec_util pci.
Une fois SPIBAR identifiée, le module MMIO (situé dans le fichier chipsec/hal/mmio.py) peut être utilisé pour extraire les différents registres du contrôleur SPI, tel que HSFS.
chipsec_main réalise automatiquement l’extraction des registres nécessaires. Par exemple, le plugin spi_fdopss (SPI Flash Descriptor Security Override) récupère automatiquement le contenu du registre HSFS (Hardware Sequencing Flash Status Register, offset 0x4 de SPIBAR) et ses bits tels que FDOPSS, FLOCKDN etc. en indiquant si leurs valeurs sont conformes d’un point de vue sécurité.
Encore une fois, la même opération peut être effectuée manuellement, sans se baser sur les fichiers de configuration, à l’aide de chipsec_util. Chipsec connaît déjà un certain nombre d’espaces mémoire importants, il est donc possible de ne spécifier que son nom :
Il est aussi possible de spécifier l’offset et la taille d’un registre (par exemple, 0x4 pour HSFS) :
Il est par contre ensuite nécessaire d’évaluer manuellement la valeur retournée par Chipsec et sa conformité.
La liste des espaces mémoire connus de Chipsec peut être obtenue avec la commande :
4.7 Autres accès
Par souci de place dans l’article, nous ne pouvons pas présenter tous les moyens d’accès utilisés par Chipsec, mais nous pouvons néanmoins préciser que l’outil gère les accès aux informations exposées par le CPU (cpuid et MSR) ainsi que les accès par le protocole SPI.
À l’instar de PCI et MMIO, Chipsec utilise un ioctl (code 0x7 notamment) pour demander au module noyau de relever les registres du CPU via les instructions cpuid. Aucun control n’est utilisé puisque le mode de fonctionnement de cpuid est fixe quelle que soit la plateforme et les valeurs d’entrée peuvent donc être définies directement dans les modules Python (tels que le font cpu_info.py et spectre_v2.py). Ces derniers exécutent ensuite la fonction cpuid() de chipsec/hal/cpu.py, qui elle-même fait appel à cpuid() du module chipsec/helper/linux/linuxhelper.py. Enfin, ce dernier fait appel au driver au travers de l’ioctl et récupère les résultats de la requête à travers les registres.
Notons également que l’accès aux paramètres de configuration du CPU via les MSR est également possible au travers du driver Chipsec (codes IOCTL 0x5 pour la lecture et 0x6 pour l’écriture).
L’extraction de la flash SPI (également abordée dans l’article sur les relevés de configuration), fonctionne différemment et n’utilise pas directement le driver. L’opération est possible via la commande chipsec_util.py spi dump qui fait appel au script chipsec/utilcmd/spi_cmd.py. Après avoir identifié la taille de la région BIOS de la flash SPI pour fixer une limite de dump (il ne récupère que cette région ainsi que celle qui lui précède, le descripteur de la Flash), les fonctions de lecture du module chipsec/hal/cpu.py sont sollicitées : read_spi_to_file(0, spi_size, out_file), read_spi(0, spi_size) et spi_reg_read(FDATAN). Comme discuté précédemment, les registres FDATAN, suite à la programmation de FDATA0 et FDADDR, permettent de lire bloc par bloc le contenu de la flash SPI. Ces registres du contrôleur SPI étant mappés en mémoire, un accès MMIO est nécessaire pour en extraire les valeurs, d’où l’utilisation finale de la fonction mmio.read_MMIO_reg(self.rcba_spi_base, reg, size), cette fois via le driver.
5. Adaptabilité de Chipsec
Un intérêt supplémentaire de Chipsec est la possibilité de l’adapter à des cas d’usages particuliers. La configuration des plateformes, au format XML, a déjà été mentionnée. Il est possible d’ajouter le support d’une plateforme à Chipsec en ajoutant un fichier correspondant. Un système d’héritage permet de facilement ajouter le support de systèmes dérivés sans préciser l’intégralité des registres, il suffit de (re)définir les registres nécessaires, comme par exemple ici pour la plateforme Whiskey Lake qui ne redéfinit qu’un registre MMIO :
L’architecture modulaire de Chipsec, à base de plugins, permet de rajouter aisément des tests de conformité en validant la valeur de registres spécifiques. Tous les plugins peuvent s’appuyer sur la configuration ainsi que sur la couche d’abstraction des accès matériels (la fameuse HAL, Hardware Abstraction Layer, évoquée plus haut, ainsi que les controls).
Un module minimal doit hériter de la classe BaseModule et implémenter au moins deux fonctions : is_supported, exécutée au démarrage de chipsec_main, et run, exécutée si la première renvoie un résultat positif. Cette deuxième méthode peut ensuite utiliser les controls et la HAL pour déterminer un succès ou un échec au test, et renvoyer cette valeur comme résultat de la fonction.
Conclusion
La complexité des systèmes actuels, illustrée dans l’article Relevé de configuration matérielle sur plateforme x86, montre l’importance d’un outil tel que Chipsec. Il ne fait aucun doute qu’un outil aussi pratique et facile d’utilisation doit faire partie de la boîte à outils de tout auditeur ou analyste cherchant à évaluer la sécurité des plateformes Intel.
L’ANSSI l’utilise aujourd’hui activement pour évaluer automatiquement les matériels bureautiques de l’administration française et ainsi savoir s’ils répondent aux exigences de sécurité [1]. Dans ce cadre, elle a publié sur son dépôt GitHub une distribution [11] prête à l’emploi sur laquelle Chipsec et d’autres outils ont été installés. Une documentation expliquant chacune des sorties de Chipsec [3] et consolidant les différents registres importants à vérifier est également disponible [12][13][14].
Si la présence d’un outil automatique facilitant le travail d’un analyste est appréciable, il faut pour autant être conscient de la dépendance qu’elle entraîne. En effet, l’auditeur repose sur la présence et le maintien à jour des configurations faites par les développeurs, que ce soit pour la localisation et la sémantique des registres, ou sur la validation ou l’échec des tests.
Enfin, un manque de Chipsec, lié à ses origines, est l’absence de gestion des plateformes AMD. Elles sont certes moins nombreuses sur le marché, et sans doute moins impactées par les vulnérabilités récentes, mais il ne faut pas perdre de vue cet aspect lorsqu’une plateforme de ce type est examinée.
Références
[1] ANSSI, « Exigences de sécurité matérielle pour plate-formes x86 » : https://www.ssi.gouv.fr/guide/exigences-de-securite-materielles/
[2] Intel, « Platform Security Assessment Framework » : https://github.com/chipsec/chipsec
[3] ANSSI, « Modules Chipsec » : https://github.com/ANSSI-FR/chipsec-check/blob/master/doc/output/modules_chipsec.pdf
[4] C. Kallenberg et R. Wojtczuk, « Speed Racer: Exploiting an Intel Flash Protection Race Condition » : https://bromiumlabs.files.wordpress.com/2015/01/speed_racer_whitepaper.pdf
[5] C. Kallenberg, X. Kovah, J. Butterworth, et S. Cornwell, « SENTER Sandman: Using Intel TXT to Attack BIOSes » : https://conference.hitb.org/hitbsecconf2014kul/materials/D1T1%20-%20SENTER%20Sandman%20-%20Using%20Intel%20TXT%20to%20Attack%20BIOSes.pdf
[6] C. Kallenberg, X. Kovah, J. Butterworth, et S. Cornwell, « All your boot are belong to us », présenté à CanSecWest : https://cansecwest.com/slides/2014/AllYourBoot_csw14-mitre-final.pdf
[7] D. Oleksiuk, « Exploiting AMI Aptio firmware on example of Intel NUC » : http://blog.cr4.sh/2016/10/exploiting-ami-aptio-firmware.html
[8] R. Wojtczuk et C. Kallenberg, « Attacks on UEFI Security », présenté à CanSecWest : https://cansecwest.com/slides/2015/AttacksOnUEFI_Rafal.pptx
[9] D. Oleksiuk, « Exploiting UEFI boot script table vulnerability » : http://blog.cr4.sh/2015/02/exploiting-uefi-boot-script-table.html
[10] « The PCI ID Repository » : https://pci-ids.ucw.cz/
[11] ANSSI, « Tools for testing requirements » : https://github.com/anssi-fr/chipsec-check
[12] ANSSI, « Mindmap SPI Protection » : https://github.com/ANSSI-FR/chipsec-check/blob/master/doc/output/SPI%20Protection.pdf
[13] ANSSI, « Mindmap SMRAM Protection » : https://github.com/ANSSI-FR/chipsec-check/blob/master/doc/output/SRAM%20Protection.pdf
[14] ANSSI, « Mindmap CPU Options» : https://github.com/ANSSI-FR/chipsec-check/blob/master/doc/output/CPU%20Options.pdf