Sécurité des systèmes d’exploitation – TP
Amaury Buffet, inspiré de celui de M Franck Pommereau
1. Exploitation d’un débordement de tampon
On considère le programme suivant (password.c ) qui pour chaque argument de la ligne de commande demande un mot de passe et vérifie s’il vaut « secret »
#include <stdio.h>
#include <string.h>
int check_password (char *password) {
int result = 0;
char buffer [20];
printf (" password: ");
gets ( buffer );
if ( strcmp(buffer , password) == 0) { result = 1; }
return result;
}
int main (int argc , char argv[]) {
int i ;
for ( i =1; i<argc; i++) { printf (argv[ i ]);
if ( check_password("secret")) { printf ("success\n");
} else {
printf ("failed\n");
} }
}
1.Identifiez le débordement de tampon susceptible de se produire.
2. Pourquoi l’avertissement qui a lieu lors de la compilation est-il valable en général et non seulement sur ce programme ?
3. Comment peut-on exploiter le débordement de tampon pour obtenir un succès sans connaître le bon mot de passe ?
4. Faites cette exploitation, directement et sous gdb.
5. Avec gdb, récupérez les informations permettant l’exploitation par injection de code. Dessinez la pile au moment du débordement, indiquez les adresses et valeurs récupérés sous gdb.
6. Quelles différences pouvez-vous constater entre deux examens successifs avec gdb ? 7. Dans quelle mesure ces différences gênent-elles l’exploitation par injection de code ? 8. Quelle serait la structure d’une chaîne permettant cette exploitation ?
9. Réalisez un déni de service (plantage de l’application) par débordement de tampon.
10. Inversez les déclarations des lignes 5 et 6 et réessayez les exploitations réalisées précédemment.
11. Quelles différences constatez-vous ? Expliquez.
12. Ce programme est sensible à un bogue de format, mettez-le en évidence.
13. Avec gdb, vérifiez que l’adresse de base du tampon débordé est toujours située à la même distance d’une adresse disponible sur la pile. Quelle est cette adresse ?
14. Expliquez comment on peut récupérer cette adresse grâce au bogue de format.
15. Ecrivez un programme exploitant les deux failles pour injecter et exécuter du code dans le programme vulnérable.
2. Recherche d’information dans un binaire
On reprend le programme password.c du TP précédant.
1. Changez le mot de passe du programme, et recompilez sans l’option -ggdb. Appliquez dessus les outils strip et sstrip.
L’outil sstrip fait partie de la suite ELF Kickers, il est disponible sur la page de ressources ou sur http://www.muppetlabs.com/breadbox/software/elfkickers.html
2. Récupérez le programme recompilé d’un autre groupe et examinez-le dans le but de retrouver le nouveau mot de passe.
On se donne une version modifiée du programme précédent (hidepass.c) qui cache le mot de passe (et corrige les vulnérabilités) :
#include <stdio.h>
#include <string.h>
#define KEY 42
void decrypt (char *str) { int i ;
char k = KEY;
for ( i =0; str [ i ] != ’\0’; i ++) { str [ i ] = str [ i ] ˆ k;
k++;
} }
int check password (char *password) { char buffer [20];
char *new_line;
int result = 0;
printf (" password: ");
fgets ( buffer , 19, stdin );
new_line = index(buffer , ’\n’);
if ( new_line != NULL) {
*new_line = ’\0’;
}
if ( strcmp(buffer , password) == 0) { result = 1; } return result;
}
int main (int argc , char *argv[]) { int i ;
char passwd[] = "YNO_K[";
decrypt(passwd);
for ( i =1; i<argc; i++) { printf ("%s", argv[ i ]);
if ( check password(passwd) == 1) { printf ("success\n");
} else {
printf ("failed\n");
} } }
3. Expliquez pourquoi ce type de protection est forcément contournable.
4. Contournez cette protection à l’aide de gdb.
5. Contournez-la en surchargeant une fonction de la librairie standard C.
Pour surcharger getpid (2), on commence par réimplenter la fonction :
1 #include <sys/syscall . h>
2 #include <sys/types.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 pid t getpid (void) {
6 printf ("Hello, world!\n");
7 return syscall (SYS getpid);
8 }
On compile avec :
# gcc -Wall -fPIC -shared -o getpid.so getpid.c
On lance le programme cible (ici bash (1)) avec :
# LD_PRELOAD=./getpid.so bash -c ’echo
$$’ Hello, world!
3358
On utilisera dlopen (3) et dlsym (3) pour charger la fonction d’origine depuis la librairie C (si on doit l’appeler).
6. Ce code est embarqué dans un binaire compilé statiquement (programme hidepass) et utilisant une autre clef que 42 ainsi qu’un autre mot de passe. Utilisez gdb sur ce binaire pour retrouver le mot de passe pendant l’exécution.
7. Proposez et implantez une méthode (ou plusieurs) de protection du mot de passe offrant un bon compromis entre robustesse et simplicité.