Vulnérabilités aux injections de NOP sur cartes à puce Introduction

Vulnérabilités aux injections de NOP sur cartes à puce
Franck De Goër
Tuteur : Marie-Laure Potet
Ensimag - Verimag
16 mai 2013
Introduction
Les cartes à puces se sont généralisées depuis les années 80, et contiennent aujourd’hui des
données sensibles (cartes bancaires, e-passeports, badges d’accès, etc.). Il est donc primordial qu’elles
présentent une robustesse maximale à tout type d’attaque, que ce soit matériel ou logiciel. Par
exemple, il est préférable qu’une personne malveillante ne soit pas en mesure d’utiliser une carte
bleue sans connaître son code PIN. À ce titre, de même que l’on teste les serrures de coffre-fort
d’une part, et la résistance de la porte dudit coffre d’autre part, la sécurité du code
ainsi
que la
protection matérielle de la carte doivent être éprouvées.
Nous nous intéressons dans ce papier à l’évaluation de la robustesse d’un code s’exécutant sur
carte à puce, face aux attaques classiques du domaine (ces attaques sont introduites en section 1, et
largement expliquées dans le papier de Bar-El, Choukri, Naccache, Tunstall et Whelan [
1
]). Nous
nous intéresserons particulièrement à la possibilité de détecter au niveau source des vulnérabilités
pouvant être exploitées par un attaquant durant l’exécution du programme.
Les autorités de certification de cartes à puce (CESTI
1
) ont besoin de vérifier la robustesse d’un
code avant de le valider. Il est donc nécessaire de développer des outils d’analyse qui vont dans
ce sens, c’est-à-dire permettant la détection automatisée de vulnérabilités. À l’heure actuelle, leur
protocole de validation, détaillé dans la partie 2.1, est basé sur des tests exhaustifs en brute force,
indépendamment de la sémantique du code testé (nous y reviendrons dans la section 2.1). L’approche
Lazart
(introduite dans le papier de Potet, Mounier et Vivien [
2
], et sur laquelle nous revenons en
section 2.2), quant à elle, bien que non exhaustive, permet de détecter les vulnérabilités au niveau
du code source. L’avantage de cette approche est qu’elle reste praticable même lorsque le modèle de
faute est complexifié (
e.g.
l’attaquant peut introduire un nombre quelconque de fautes). Elle est
complémentaire à l’approche du CESTI, en ce sens qu’elle permet de mettre en évidence des points
sensibles du programme qu’il est particulièrement intéressant de tester. À l’heure actuelle,
Lazart
ne
détecte que les vulnérabilités liées aux inversions de test, comme détaillé section 2.2. L’objectif de ce
papier est d’étendre cette approche aux attaques
NOP
. Ces attaques, décrites plus précisément en sec-
tion 3, consistent à empêcher l’exécution de certaines instructions d’un programme lors de l’exécution.
Dans la section 1, nous décrirons le principe d’une attaque laser sur carte à puce et ses consé-
quences. En 2, nous verrons les différentes approches existantes pour détecter des vulnérabilités
aux attaques laser. Les sections 3 et 4 présentent notre contribution au domaine : en 3, nous ferons
un descriptif détaillé du type d’attaque étudié et ses conséquences ; et en 4 nous présenterons une
implémentation s’insérant dans l’approche Lazart pour détecter ce type d’attaques.
1
. Centre d’Évaluation de la Sécurité des Technologies de l’Information : organisme chargé de valider la robustesse
des codes exécutés sur carte avant commercialisation
1
Franck De Goër Injections de NOP sur cartes à puce
Table des matières
1 Principe d’une attaque laser 3
2 Détections de vulnérabilité aux injections de faute : approches existantes 4
2.1 Au niveau binaire : brute-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Au niveau source : Lazart ................................. 4
2.2.1 Coloration du graphe de flot . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2.2 Générationdemutants............................... 6
2.2.3 Tests symboliques sur les mutants . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Sensibilité à l’introduction de NOP ............................. 7
2.4 Pertinence des NOP ..................................... 7
3 Attaques de type JUMP NOP 7
3.1 Boucle while ........................................ 8
3.2 Structure if|elsif|else ................................. 9
3.3 Retoursdefonction..................................... 10
4 Implémentation et résultats 11
4.1 Noppy............................................ 11
4.1.1 Inclusion dans l’approche Lazart ......................... 11
4.1.2 Algorithme de base d’ajout d’arcs . . . . . . . . . . . . . . . . . . . . . . . . 12
4.2 Sur un exemple : verify .................................. 14
4.2.1 Mutation et coloration du CFG . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.2.2 Production de codes mutants et analyse dynamique sur le CFG modifié . . . 15
A Efficacité des détections au niveau source et au niveau binaire 21
B Deux conséquences differentes à une attaque de type NOP sur une boucle while 21
C Mutant de verify pour analyse dynamique 22
2
Franck De Goër Injections de NOP sur cartes à puce
1 Principe d’une attaque laser
Nous présentons dans cette section le principe général d’une attaque classique sur carte à puce :
l’attaque au laser par injection de faute. L’idée est de modifier une valeur de la mémoire afin de modi-
fier le comportement à l’exécution du programme à attaquer, et ce afin d’obtenir des informations ou
d’outrepasser des authentifications. C’est une attaque matérielle dans le sens où elle est insérée physi-
quement dans le système, mais sa répercution est directement liée au logiciel qui s’exécute sur la carte.
Dans les papiers de Pellegrini, Bertacco, Austin [
3
] et de Barenghi, Breveglieri, Koren, Pelosi,
Regazzoni [
4
] sont décrites des attaques respectivement sur RSA et AES s’exécutant sur carte à
puce. Grâce à des injections de faute dans les calculs, il est possible de récupérer la clé privée (ou la
clé symétrique dans le cas de l’AES) embarquée dans la carte. Dans ces deux cas, il s’agit d’injection
d’erreurs de calculs durant le chiffrement d’un même message afin de récupérer des informations
sur la clef. La thèse de Maria Christofi [
5
] traite dans le chapitre 9 des analyses de vulnérabilité
d’implémentations cryptographiques face aux injections de faute.
Dans ce papier, nous nous intéresserons plutôt à l’injection de faute amenant non pas à des
erreurs de calculs mais à une modification du chemin d’exécution du code sur la carte. Ci-suit un
exemple illustrant le principe de ce type d’injection de faute.
1int triesLeft = 2;
2
3int verify(char buffer[], int ofs, int len) {
4int i;
5/* No comparison if PIN is blocked */
6if(triesLeft < 0)
7return EXIT_FAILURE;
8
9/* Main Comparison */
10 for (i = 0; i < len; i++) {
11 if(buffer[ofs + i] != pin[i]) {
12 triesLeft--;
13 authenticated = 0;
14 return EXIT_FAILURE;
15 }
16 }
17
18 /* Comparison is successful */
19 triesLeft = maxTries;
20 authenticated = 1;
21 return EXIT_SUCCESS;
22 }
Figure 1 – Code de vérification du code PIN
Ce code est chargé de vérifier le code PIN entré par l’utilisateur de la carte. Nous voyons ici
que si l’utilisateur entre trois codes PIN erronés, la fonction renvoie
EXIT_FAILURE
, ce qui a pour
effet de déclencher une contre-mesure (par exemple un blocage de la carte). Dans ce cas précis,
l’objectif de l’attaquant est de sortir avec la valeur
EXIT_SUCCESS
, ou encore de ne pas sortir avec
la valeur
EXIT_FAILURE
qui peut entraîner le blocage de la carte. Pour ce faire, il peut par exemple
injecter une faute consistant à forcer le résultat du test de la ligne 6 à
FALSE
afin de disposer
de plus de trois essais. Dans la même idée, l’attaquant peut empêcher l’exécution de l’instruc-
tion
triesLeft––
pour ne pas voir le nombre d’essais diminuer. C’est le principe d’injection de
3
Franck De Goër Injections de NOP sur cartes à puce
faute : le comportement à l’exécution peut être modifié pour amener le système dans un état imprévu.
L’injection de faute peut se faire de plusieurs manières, mais la principale utilisée sur carte à
puce est l’attaque au laser : l’éclairage au laser d’un transistor l’amène régulièrement à introduire
une erreur de valeur (chaque attaque de ce genre a un taux de réussite d’environ 20%). Il est donc
possible de changer la valeur de tests, de modifier des instructions ou encore de modifier des adresses
de saut. L’attaque qui nous intéresse particulièrement dans la suite est l’introduction de
NOP
à la
place d’autres instructions, et notamment à la place de sauts, conditionnels ou non. L’introduction
d’un
NOP
consiste à remplacer une instruction assembleur (par exemple
BRA 0x5000
ou un
JCC
,
dénotant un jump conditionnel générique
2
) en instruction
NOP
qui est l’instruction
null
: le saut est
donc remplacé par une instruction vide, et le programme continue donc sans avoir effectué le BRA.
Dans la section qui suit, nous décrivons les approches existantes pour détecter des vulnérabilités
aux injections de faute à différents niveaux (binaire, source, etc.).
2 Détections de vulnérabilité aux injections de faute : ap-
proches existantes
Il existe plusieurs approches possibles dans le but de détecter des vulnérabilités aux injections de
faute sur un exécutable.
2.1 Au niveau binaire : brute-tests
La première solution (utilisée notamment par le CESTI) est une méthode d’injection à
l’aveugle
.
À partir d’un fichier binaire, des mutants
3
sont produits, correspondant chacun à l’exécutable
original dont un octet a été remplacé par
0x00 ou 0xFF
(simulation d’une injection de faute, cf
section 2.4). Chaque mutant est exécuté. La plupart du temps, la modification d’un octet amène
à un exécutable qui ne s’exécute pas correctement, mais parfois le système est amené dans un
état imprévu (par exemple
EXIT_SUCCESS
alors que le PIN n’a pas été rentré). Pour certifier un
programme, toutes les injections de faute possibles sont testées et ne doivent pas aboutir à une
vulnérabilité. L’exhaustivité de cette méthode repose sur l’hypothèse que l’attaquant n’est en mesure
de faire qu’une unique injection de faute. Si l’on considère possible la double (voire triple) injection
de faute, le nombre de cas à couvrir devient trop important.
2.2 Au niveau source : Lazart
L’approche mise en place à
Verimag
n’a pas le même point de départ : à partir du graphe de
flot
4
(CFG) d’un programme, le but est de déterminer en combien d’injections possibles l’attaquant
peut arriver à une situation compromettant la sécurité du système. l’approche est découpée en trois
grandes étapes (correspondant aux trois blocs de la figure 2).
2.2.1 Coloration du graphe de flot
À partir du code dont on veut évaluer la robustesse, le graphe de flot est généré (à l’aide d’une
librairie
llvm
). Ensuite, étant donné un noeud du graphe dit critique (noeud à atteindre ou à éviter
2. Par exemple JEQ ou JNE
3. Un mutant correspond à une version modifiée du binaire original
4
. Un graphe de flot est un graphe décrivant les chemins possibles que peut prendre une exécution. Chaque noeud
correspond à un bloc d’instructions séquentielles, et chaque arc correspond à un saut (conditionnel ou inconditionnel)
4
Franck De Goër Injections de NOP sur cartes à puce
KLEE
CFG
coloring
test directives
inconclusiveattack paths
mutant.ll
robustness "proof"
appli.ll
attack objectives
mutation points mutation
generation appli.ll
Figure 2 – Schéma de l’approche Lazart
pour l’attaquant, e.g.
EXIT_SUCCESS
ou
EXIT_FAILURE
) l’outil
Lazart
colorie le CFG, en mettant
en évidence les noeuds vulnérables à une injection de faute. On fournit en entrée du programme de
colorisation un noeud à atteindre (par exemple
EXIT_SUCCESS
). En sortie, les noeuds conduisant
inévitablement vers le noeud à atteindre sont en vert, les noeuds ne pouvant plus conduire au but
sont en rouge. Les noeuds pouvant amener soit dans le rouge soit dans le vert (selon le résultat
des tests) sont en jaune, ou en orange s’ils ont un fils direct qui est rouge. La figure 3 illustre sur
l’exemple du PIN la coloration d’un CFG. Dans ce cas, le but à atteindre est le noeud
SUCCESS
. On
voit qu’une fois un noeud
FAILURE
atteint, il n’est plus possible d’atteindre le noeud
SUCCESS
, c’est
pourquoi ces noeuds ainsi que leurs fils sont rouges. L’algorithme de coloration de graphe a été écrit
et implémenté par J. Vivien [6].
CFG de la fonction 'verify' colorié (objectif : atteindre SUCCESS)
entry:
triesLeft < 0?
T F
FAILURE
bb1
bb7
bb5:
T F
return:
bb2:
T F
SUCCESS
FAILURE bb4:
Figure 3 – Exemple de coloration d’un CFG par Lazart
5
1 / 23 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !