Les Buffer-Overflows


<< Illustration de la segmentation Les stack-based overflows >>


I°) 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 :

    //exemple-overflow.c : Dépassement de mémoire tampon

    #include <stdio.h>

    void demander_nom() {
      char buffer_nom[20];

      printf("Entrez votre nom\n");
      scanf("%s",&buffer_nom);

      printf("Votre nom est %s\n",buffer_nom);
    }

    int main() {
      demander_nom();

      return 0;
    }
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 please!
   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 ...


<< Illustration de la segmentation Les stack-based overflows >>



14 Commentaires
Afficher tous


matricias 13/12/13 15:57
c'est très bien 'ça marche' merci a vous pour c'ette information précieuse

FrizN 10/06/13 07:45
Ce qui est important dans cette valeur, c'est le \x00. Par exemple, lors d'une exécution normale, le pointeur vaudrait 0x12345678 (stocké \x78\x56\x34\x12). En mettant une chaîne d'un caractère trop longue, on a le premier byte qui est remplacé par le byte 0, fin de chaîne : \x00\x56\x34\x12.

Anonyme 08/06/13 11:48
salut
je vais savoire si la valeur du RA est choisi par vous ou il faut qu'il egale a 0x00563412 si oui pourquoi

FrizN 03/06/13 08:21
Je ne comprends pas trop la question, qu'est-ce qui bloque dans cette valeur ?




Commentaires désactivés.

Apprendre la base du hacking - Liens sécurité informatique/hacking - Contact

Copyright © Bases-Hacking 2007-2014. All rights reserved.