Réaliser votre premier buffer overflow, et apprenez les bases de l’exploitation de binaire.

Dans cette article je vais tenter de vous expliquer le fonctionnement d’un stack buffer overflow, autrement dit d’un dépassement de buffer dans la pile.

Un stack buffer overflow est une vulnérabilité qui permet a un utilisateur d’écraser des valeurs dans la pile (stack) d’exécution du programme pour rediriger l’exécution du programme

 Qu’est ce que la pile d’exécution du programme ?

La pile d’exécution d’un programme est un espace dans la mémoire utilisée par le programme.
Il faut la voir comme n’importe quelle pile, une pile d’assiette par exemple, elle a un comportement dit « LIFO«  c’est à dire Last-In First-Out, en français : dernier arrivé premier sorti.
Il y a deux actions possibles avec une pile , le push et le pop.

  • Le push ajoute une valeur sur la pile comme si l’on ajouté une assiette en haut de la pile.
  • le pop retire  une valeur en haut de la pile : comme si l’on retirer une assiette de la pile.

 À quoi sert la pile dans un programme ?

La pile est utilisée par un programme pour stocker des valeurs dans la mémoire du programme ainsi que pour passer des arguments a une fonction.
Prenons l’exemple du code suivant :

 

Désassemblons la fonction main dans gdb pour voir l’appelle a la fonction somme en assembleur :

 

comme vous pouvez le voir avant le « call somme » qui , comme son nom l’indique, appelle la fonction somme.

On peut voir les deux arguments ( 0x1 et 0x2 ) ajouté dans la pile grâce à deux push des variables dans l’ordre inverse de leur passage en argument

nous afficheront la pile dans gdb avant ces deux push :

Ensuite après ces deux push :

nous pouvons voir que deux valeurs 0x1 et 0x2 on été ajouté dans la pile.

Maintenant le programme n’a plus qu’à les « poper » de la pile pour les utiliser.

Sauvegarde de l’adresse de retour sur le pile

Lorsqu’une fonction est appelée avec call , l’adresse où doit retourner le programme après l’exécution de la fonction appelée est stockée dans la pile

voici la pile avant le call:

et la pile une fois le call effectué :

nous pouvons voir que l’adresse 0x5655553a a été ajoutée sur la pile.Le programme retournera donc à cet endroit une fois exécution de la fonction somme terminée.

Comme on peut le voir c’est bien l’adresse de l’instruction après le « call somme ».
Maintenant expliquons le fonctionnement de l’instruction ret qui retourne à l’adresse de retour.
Le ret agit comme un « pop eip ». Il récupère l’adresse de retour sur la pile pour le mettre dans le registre d’instruction eip.

Le registre EIP pointe vers la prochaine instruction à exécuter.

Contrôler EIP revient donc à contrôler le flux d’exécution du programme.

Stack overflow ?

Maintenant nous savons comment fonctionne la pile et comment est appelée une fonction. Regardons comment exploiter notre premier programme vulnérable.

Le programme vulnérable :

Nous allons utiliser le programme suivant :

Compilez le programme avec la commande : gcc vuln.c -m32 -fno-stack-protector -o vuln

Exploitation du stack overflow

Le but va être de lancer la fonction evil en écrasant la valeur de retour de l’adresse stockée sur la pile.
Pourquoi se programme est vulnérable ? Car la fonction gets ne vérifie pas la taille des données entrée dans le « buffer » de 32 caractères.

On peut donc écrire plus de 32 caractères et écraser la valeur de retour situé après le buffer dans la pile.

Posons un breakpoint sur le ret de la fonction vuln : gdb-peda$ break *vuln+43
maintenant entrons quelque ‘A’ dans le buffer et affichons les valeurs dans la pile  :

nous pouvons voir que les A sont biens empilés (la valeur ascii de A est 0x41)  mais n’écrasent pas encore l’adresse de retour de la pile ( 0x565555e8 ).

lançons le programme avec plus de A, on obtient  une segmentation fault à l’adresse 0x41414141

L’adresse de retour stockée dans la pile à donc été écrasée par les ‘A’.

Maintenant écrivons un pattern dans le buffer pour voir à partir de quelle longueur de chaîne on écrase l’adresse de retour :

lançons le programme avec cette chaîne, nous obtenons une segmentation fault à l’adresse 0x35624134, demandons à notre petit script la taille correspondante :

Il faut donc écrire 44 caractères pour  écraser l’adresse de retour stockée dans la pile.
Envoyons 44 A et 4 B pour que le programme segfault a 0x42424242 ( 42 est le code ascii de B) :

Voilà, il ne reste plus qu’à modifier nos B par l’adresse de la fonction evil que l’on récupère avec gdb :

Cependant notre processeur a une architecture intel qui est en little endian. C’est a dire que les bits de poids faible sont écrit en premier. L’adresse doit donc être écrite à l’envers.

lançons notre programme avec la bonne adresse en redirigant la sortie du script python qui affiche le nombre de A puis l’adresse :

La fonction evil a bien été appelée, notre premier stack buffer overflow est réalisé !

Add a Comment

Votre adresse de messagerie ne sera pas publiée.