Débordement de tampon - allocation    Enregistrer au format PDF


par S3cur3D

Qu’est-ce qu’un buffer-overflow ?

La traduction littérale suffit à expliquer le terme : c’est un dépassement du buffer, aussi appellé dépassement de mémoire tampon en français. Cela peut arriver très fréquemment. En effet, les langages de haut-niveau laissent au programmeur le soin de vérifier la non-corruption des données, entre autres de vérifier que les longueurs limites des tableaux ne peuvent en aucun cas être dépassées dans le programme. Concrètement, si le dépassement est petit, il va juste corrompre les variables qui suivent le buffer. S’il est un peu plus grand, il peut changer la valeur des deux pointeurs SFP et return address, causant bien souvent le crash du programme, puisque ces pointeurs sont par la suite dénués de sens (par exemple, si le pointeur EIP contient une adresse où il n’y a pas d’instruction valide, le programme s’interrompt avec le message d’erreur Segmentation Fault ou Illegal Instruction). Voici un exemple simple d’overflow :

  1.     //exemple-overflow.c : Dépassement de mémoire tampon
  2.  
  3.     #include <stdio.h>
  4.  
  5.     void demander_nom() {
  6.         char buffer_nom[20];
  7.  
  8.         printf("Entrez votre nom\n");
  9.         scanf("%s",&buffer_nom);
  10.  
  11.         printf("Votre nom est %s\n",buffer_nom);
  12.     }
  13.  
  14.     int main() {
  15.         demander_nom();
  16.  
  17.         return 0; }

Télécharger

La fonction printf imprime à l’écran un texte et scanf stocke ce qui est entré au clavier dans la variable buffer_nom. Ces fonctions sont contenues dans la librairie C stdio.h, c’est pourquoi on a inclut cette librairie au début du programme. Le caractère ’\n’ est quand à lui le caractère de retour à la ligne. Voici maintenant des exemples d’éxécutions de ce programme :

   $ gcc -m32 -fno-stack-protector exemple-overflow.c -o exemple-overflow
   $ ./exemple-overflow
   Entrez votre nom
   SeriousHacking
   Votre nom est SeriousHacking
   $ ./exemple-overflow
   Entrez votre nom
   AAAAAAAAAAAAAAAAAAAAAAA
   Votre nom est AAAAAAAAAAAAAAAAAAAAAAA
   $ ./exemple-overflow
   Entrez votre nom
   AAAAAAAAAAAAAAAAAAAAAAAA
   Votre nom est AAAAAAAAAAAAAAAAAAAAAAAA
   Instruction illégale
   $

Nous avons donc l’exemple classique où l’utilisateur fournit un nom, plus petit que 20 caractères et où tout se passe bien. Dans le second exemple, on fournit exactement 23 fois le caractère ’A’. Le tableau ayant une taille de 20 octets, toutes ses cases seront remplies de A, 3 caractères à placer plus le nul byte. Par conséquent, l’espace du tableau va être dépassé et le pointeur SFP va être réécrit, en l’occurence remplacé par 0x41414100 (le caractère ’A’ s’écrivant 0x41 en hexadécimal). Nous avons donc un overflow, mais ici sans incidence sur la suite du programme, car le pointeur EBP n’a plus d’utilité après la fonction, même s’il devient 0x00414141 qui est une addresse sans signification, celà n’a pas d’effet.
Dans le troisième cas, on a fournit un caractère de plus, à savoir 24 caractères. On devine rapidement ce qui se passe : le SFP deviendra cette fois 0x41414141 et le return address 0x00563412. L’EIP va donc pointer vers 0x12345600 après le popping de demander_nom(), où il va trouver une instruction qui ne sera pas valide, d’où le crash du programme.
On s’en doute, l’exploitation des buffer-overflows va consister en l’exploitation de ce type de faille. Cet exemple est basé sur un overflow dans la pile. L’exploitation associée sera dénommée stack-based overflow et sera notre premier "BoF" (enfin !) dans la partie suivante.

Attention

Afin de bien comprendre d’où viennent et comment marchent les buffer overflows, j’utilise ici les techniques historiques d’exploitation, qui sont désormais rarement utilisables à cause des protections mises en place. Il faut les désactiver pour que les exemples marchent :

 désactiver ASLR (adresses aléatoires). En tant que root :

       # echo "0" > /proc/sys/kernel/randomize_va_space


 désactiver la pile non exécutable. Lors de la compilation :

       $ gcc -z execstack ...


 désactiver le stack protector (cookie avant le SFP). Lors de la compilation :

       $ gcc -fno-stack-protector ...


 compilation en mode 32-bits (si vous êtes sur une machine 64-bits). Lors de la compilation :

      $ gcc -m32 ...

Documentations publiées dans cette rubrique