TD Vulnérabilités par canaux auxiliaires
Introduction
Dans ce TD on va tenter de réaliser une attaque type 'Spectre' dans un environnement contrôlé.
Cette attaque exploite une vulnérabilité matérielle présente dans de nombreux processeurs et permet de passer outre l'isolation intra et inter processus. Comme il s'agit d'une vulnérabilité matérielle liée au design et au principe de fonctionnement des processeurs, il est assez difficile de s'en défendre, même si les fabricants de CPU y travaillent.
Ce qu'on va voir
- Caches CPU
- Exécution 'out-of-order' et prédiction de branchement dans les CPU
- Exploitation du cache comme canal auxiliaire
- Vulnérabilité Spectre
Compilation des codes
Tous les codes devront être compilés comme suit:
gcc -mach=native -o <binaire> -c <fichier.c>
Utilisation du cache comme canal auxiliaire
Meltdown et Spectre utilisent le cache comme canal auxiliaire pour révéler un secret protégé. La technique utilisée est dite FLUSH + RELOAD (vidage et rechargement). On va étudier cette technique en premier.
Fonctions utiles
Etape 1 : mesure du temps d'accès au cache
Fichier à compiler : cachetime.c
Complétez cachetime.c pour mesurer les différences de temps d'accès entre des données dans le cache et hors cache. Exécutez le programme une dizaine de fois, en déduire un seuil approximatif qui différencie ces deux temps d'accès. On se servira de ce seuil pour déterminer si une donnée est dans le cache ou non.
Etape 2 : le cache comme canal auxiliaire
Fichier à compléter / compiler : flushreload.c
L'idée est d'utiliser le temps d'accès au cache pour révéler un secret.
On suppose une fonction victim
qui utilise le secret comme index pour accéder à un tableau. Ce secret est
supposé inaccessible. La technique qu'on utilise pour révéler le secret manipulé par victim
est appelée FLUSH+RELOAD.
- Vider complètement le tableau de la mémoire cache
- Appeler la victime. Cette action provoque le chargement dans le cache d'une ligne qui dépend du secret
- Recharger le tableau dans le cache et mesurer le temps de rechargement de chaque élément. Si le temps est court, l'élément était déjà dans le cache et c'est cet élément que la victime a utilisé : on connait alors le secret.
- Complétez
flushreload.c
- Pourquoi pas simplement
array[256]
? - Pourquoi utiliser un décalage (rôle de
DELTA
) ? - Est ce que la technique est fiable à 100% ? Pourquoi ?
Exécution dans le désordre
Fichier à compléter / compiler : spectreexperiment.c
Spectre repose sur l'exécution dans le désordre, qui est une optimisation importante utilisée dans tous les CPU modernes pour maximiser le taux d'utilisation de ses unités de calcul (et donc maximiser les performances d'exécution).
Etape 3
- Exécuter le programme (plusieurs fois). Qu'observez-vous ?
- Ligne 67, remplacer par "
victim(i+20);
". Que se passe-t-il ? Pourquoi ? Remettez le code initial. - Commentez les lignes 66 et 71 (flush de size). Est-ce que l'attaque fonctionne toujours ? Pourquoi ?
- Décommentez les lignes 66 et 71.
Attaque 'Spectre'
Fichier à compléter / compiler : spectreattack.c
Dans ce code, on suppose une fonction restrictedAccess
qui permet l'accès à un buffer limité pour simuler une sandbox.
Le secret est en dehors de la sandbox. L'accès au secret n'est possible qu'au travers de la fonction restrictedAccess
(c'est à dire qu'on a pas le droit de le lire directement). Le but est d'afficher le secret.
Etape 4
- Exécutez le programme et déterminez si vous êtes capable de déterminer la valeur secrète. Pourquoi le résultat n'est pas fiable ? Exécutez le programme un nombre suffisant de fois pour être sûr du secret.
Etape 5 : amélioration de la fiabilité de l'attaque.
Fichier à compléter / compiler : spectreattackimproved.c
L'idée est d'automatiser la répétition de l'attaque et de maintenir un tableau de scores pour chaque succès de cache. C'est une approche statistique. Le secret est supposé être la valeur pour laquelle on a eu le plus de succès de cache.
- Exécutez le programme. Qu'observez vous ?
- Comment faire pour que le programme trouve réellement le secret qui n'est définitivement pas 0 ?
Etape 6 : détermination de tout le secret.
Modifiez spectreattackimproved.c
pour qu'elle retourne tout le secret (toute la chaîne de caractère).