
Dans le paysage de l'informatique moderne, les préoccupations en matière de sécurité dépassent les vulnérabilités du système d'exploitation (OS) et les bugs logiciels. En profondeur sous les abstractions, nos processeurs ont évolué vers des microarchitectures complexes—pipelines, caches, tampons, et moteurs d'exécution—conçus pour extraire des performances maximales. Ironiquement, ces fonctionnalités introduisent de nouveaux risques subtils pour la sécurité, donnant lieu à ce que l'on appelle les attaques microarchitecturales. Ces attaques exploitent le partage involontaire—et la fuite—de l'état microarchitectural entre des applications s'exécutant simultanément, parfois même dans des logiciels parfaitement sécurisés.
Ce post de blog complet vise à démystifier les attaques microarchitecturales, en couvrant :
Que vous soyez débutant, chercheur, développeur logiciel ou professionnel de la cybersécurité, ce guide vous équipera pour comprendre ces puissantes attaques modernes—et comment s'en défendre.
Les attaques microarchitecturales sont des techniques d'exploitation qui tirent parti des fuites d'information involontaires dans la conception de bas niveau du matériel d'un processeur.
Contrairement aux exploits logiciels typiques, les attaques microarchitecturales ne nécessitent aucun bug de programmation dans l'application ou le système d'exploitation. Elles exploitent plutôt la manière dont les CPU modernes tentent de maximiser les performances, par exemple en partageant les caches ou en réordonnant les instructions.
Les CPU modernes partagent des structures matérielles essentielles entre les applications et même les machines virtuelles, telles que :
Parce que ces structures ne sont pas parfaitement isolées, un processus peut souvent observer ou inférer les effets d’un autre. Les attaquants exploitent ce partage implicite pour extraire des secrets en observant des effets physiques indirects (comme de légers changements de temps d'accès à la mémoire).
Il existe deux grandes catégories :
Les canaux cachés créent une voie de communication entre deux acteurs (émetteur et récepteur) non prévue par la conception du système. Une application module une ressource partagée, tandis qu'une autre observe ces modifications pour reconstruire un message.
Exemples :
Les attaques par canaux latéraux fuient des informations sensibles sans communication directe. Plutôt, elles exploitent des informations “déversées” par l'activité de la victime.
Exemples :
Les deux canaux permettent à un processus de déduire des informations sur un autre—parfois à travers les limites de conteneurs, de VM ou d'utilisateurs.
Les systèmes de calcul hétérogènes comprennent plusieurs types de processeurs (CPU à usage général, GPU, FPGA, accélérateurs IA, etc.) dans la même plate-forme, partageant souvent une partie de la mémoire et/ou de l'état microarchitectural.
Supposons qu'un GPU et un CPU partagent une région de cache. Un processus à faible privilège s'exécutant sur le GPU pourrait “apprêter” le cache, et un processus à haut privilège s'exécutant sur le CPU pourrait involontairement révéler des secrets à travers ses accès mémoire. Ensuite, le processus à faible privilège pourrait observer les changements, inférant des informations protégées.
RISC-V est un jeu d'instructions modulaire et open-source, gagnant rapidement en popularité pour la recherche et les systèmes embarqués commerciaux. Bien que les attaques microarchitecturales soient bien étudiées sur x86 et ARM, des recherches récentes montrent que RISC-V est également susceptible.
À Retenir : Aucun jeu d'instructions ni matériel open-source n'est immunisé—tous les CPU avec microarchitecture partagée sont vulnérables à moins d'être spécifiquement renforcés.
Un domaine novateur : les attaques moteur de pile (Source)
Si l'attaquant et la victime partagent un CPU, en effectuant des opérations de pile sur mesure et en observant le timing résultant, l'attaquant peut inférer quel type d'activité de pile la victime a récemment exécuté.
Spectre et Meltdown (2018) ont fait comprendre au monde que les attaques microarchitecturales ne sont pas qu'une théorie—elles affectent des milliards d'ordinateurs.
[Processus Victime] [Processus Attaquant]
Exécute une instruction Prime le cache, tempore les accès
sur des données secrètes Décode les changements dus à l'activité de la victime
---[Partager physiquement le cache]---
Prime+Probe est une attaque classique qui fonctionne comme suit :
Comme placer des pièces sur tous les sièges d'un théâtre (prime), demander à quelqu'un d'autre d'entrer (victime), puis vérifier quels sièges sont vides (probe)—révélant où la victime s'est assise, sans l'observer directement.
Des attaques récentes ciblent l'optimisation du moteur de pile :
Il est important de souligner : les attaques pratiques sur les systèmes de production sont illégales sans consentement. Cependant, les mesures de performance qui révèlent des canaux latéraux de timing peuvent être effectuées sur vos propres machines de test pour la recherche et la défense.
Sonde de timing simple pour vérifier le partage de cache (par ex. dans les machines virtuelles).
#!/bin/bash
buffer=/tmp/testmem
size=1024000
# Allouer un grand tampon
dd if=/dev/urandom of="$buffer" bs=1K count=1000
# Accéder à répétition à la mémoire pour "primer" le cache
function prime_cache {
for i in $(seq 1 $size); do
tail -c +$i "$buffer" | head -c 1 >/dev/null
done
}
# Temps d'accès
function time_access {
/usr/bin/time -f "%e" dd if="$buffer" of=/dev/null bs=1K count=1000 2>&1
}
echo "Prime le cache..."
prime_cache
echo "Temps d'accès en lecture..."
time_access
# Maintenant demander à un autre processus d'exécuter une charge de travail intensive en mémoire et répéter
# Comparez pour voir si le timing change, indiquant une contention de cache !
Interprétez des changements significatifs comme preuve de contention de cache avec d'autres processus—potentiellement permettant des attaques Prime+Probe.
Une méthode plus précise utilise le module time de Python et des tableaux numpy pour des motifs d'accès mémoire répétitifs.
import numpy as np
import time
# Allouer un grand tableau
arr = np.zeros((1024 * 1024 * 10,), dtype=np.uint8)
def probe_access():
ts = time.time()
# Accéder à tous les éléments pour forcer le chargement du cache
for i in range(0, len(arr), 64):
arr[i] += 1
te = time.time()
print(f"Temps d'accès : {te - ts:.6f} seconds")
# Première exécution : devrait être froide (peut déclencher une erreur de page)
probe_access()
# Deuxième exécution : le cache est probablement chaud
probe_access()
Maintenant, dans un second terminal (ou processus distinct), exécutez un script dépensier en mémoire (par ex., stress-ng ou similaire), qui évincera les lignes de cache. Exécutez à nouveau probe_access() et observez l'augmentation du temps.
Si vous constatez des temps d'accès plus longs après l'exécution d’un autre processus, cela signifie que le cache de votre système est susceptible d'attaques par timing.
Étant donné la persistance des attaques microarchitecturales, que peuvent faire les défenseurs de la sécurité ?
# Vérifier les fonctionnalités CPU liées au flush
grep . /proc/cpuinfo | grep -E 'flush|clflush|clwb'
# Peut afficher : clflush, indiquant des instructions disponibles pour que le logiciel purge les caches
De nombreux vendeurs de CPU introduisent des fonctionnalités telles que :
Cependant, la plupart des CPU déployés sont encore susceptibles, particulièrement dans les environnements de cloud ou avec du matériel complexe.
Les attaques microarchitecturales ne sont plus une "curiosité théorique". À mesure que nos processeurs deviennent plus optimisés—et plus partagés—les subtilités de leurs conceptions internes deviennent des outils puissants entre les mains des attaquants qualifiés.
Particulièrement dans les systèmes hétérogènes, où les CPU, GPU et accélérateurs partagent l'état microarchitectural, les canaux cachés et latéraux ne sont pas seulement possibles—ils sont courants. Les attaques récentes contre les CPU RISC-V et le moteur de pile démontrent l'universalité et la pertinence persistante de ces risques, même pour les nouvelles architectures et optimisations.
Restez à jour, testez vos propres environnements, et exigez une meilleure isolation—dans le logiciel comme dans le matériel.
Ce post est à des fins éducatives uniquement. Testez toujours dans des environnements sûrs et contrôlés.
Si vous avez trouvé ce contenu utile, imaginez ce que vous pourriez accomplir avec notre programme de formation élite complet de 47 semaines. Rejoignez plus de 1 200 étudiants qui ont transformé leur carrière grâce aux techniques de l'Unité 8200.