# Hitcon Training Magicheap

The goal of this challenge is to print the flag.

Let's take a look at the binary and libc:

```
$ ./libc-2.23.so
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 5.4.0 20160609.
Available extensions:
  crypt add-on version 2.1 by Michael Glad and others
  GNU Libidn by Simon Josefsson
  Native POSIX Threads Library by Ulrich Drepper et al
  BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
$ file magicheap
magicheap: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=7dbbc580bc50d383c3d8964b8fa0e56dbda3b5f1, not stripped
$ pwn checksec magicheap [*] '/Hackery/pod/modules/unsortedbin_attack/hitcon_magicheap/magicheap'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
$ ./magicheap
--------------------------------
       Magic Heap Creator       
--------------------------------
 1. Create a Heap               
 2. Edit a Heap                 
 3. Delete a Heap               
 4. Exit                        
--------------------------------
Your choice :
```

So we can see that we are dealing with `libc-2.23.so`. Also for the binary, we are dealing with a `64` bit binary with a Canary and NX. When we run the binary, it gives us a prompt to `create/edit/delete` heaps.

## Reversing

When we take a look at the `main` function, we see this:

```
void main(void)

{
  int menuChoice;
  char input [8];
 
  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stdin,(char *)0x0,2,0);
  do {
    while( true ) {
      while( true ) {
        menu();
        read(0,input,8);
        menuChoice = atoi(input);
        if (menuChoice != 3) break;
        delete_heap();
      }
      if (3 < menuChoice) break;
      if (menuChoice == 1) {
        create_heap();
      }
      else {
        if (menuChoice == 2) {
          edit_heap();
        }
        else {
LAB_00400d36:
          puts("Invalid Choice");
        }
      }
    }
    if (menuChoice == 4) {
                    /* WARNING: Subroutine does not return */
      exit(0);
    }
    if (menuChoice != 0x1305) goto LAB_00400d36;
    if (magic < 0x1306) {
      puts("So sad !");
    }
    else {
      puts("Congrt !");
      l33t();
    }
  } while( true );
}
```

We can see that it is essentially a menu prompt. However we can see there is an additional menu option not displayed (`4869`). If we choose that option and the bss variable `magic` stored at `0x6020c0` is greater than or equal to `0x1306`, it will run the `l33t` function. Which we see gives us the flag:

```
void l33t(void)

{
  system("cat ./flag");
  return;
}
```

Next up we have the `create_heap` function:

```

void create_heap(void)

{
  int sizeInp;
  size_t mallocSize;
  void *ptr;
  long in_FS_OFFSET;
  int i;
  char local_18 [8];
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  i = 0;
  do {
    if (9 < i) {
code_r0x00400a31:
      if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
        __stack_chk_fail();
      }
      return;
    }
    if (*(long *)(heaparray + (long)i * 8) == 0) {
      printf("Size of Heap : ");
      read(0,local_18,8);
      sizeInp = atoi(local_18);
      mallocSize = SEXT48(sizeInp);
      ptr = malloc(mallocSize);
      *(void **)(heaparray + (long)i * 8) = ptr;
      if (*(long *)(heaparray + (long)i * 8) == 0) {
        puts("Allocate Error");
                    /* WARNING: Subroutine does not return */
        exit(2);
      }
      printf("Content of heap:");
      read_input(*(undefined8 *)(heaparray + (long)i * 8),mallocSize,mallocSize);
      puts("SuccessFul");
      goto code_r0x00400a31;
    }
    i = i + 1;
  } while( true );
}
```

So we can see, it's a pretty standard heap allocation function. It prompts us for a size, then mallocs it and stores it in the bss array `heaparray` at `0x6020e0`. It also allows us to scan in as much data into the chunk as we specified it's size. Notice how it doesn't save the size of the chunk. Also we can see that it limits us to `10` chunks. Next up we have the `edit_chunk` function:

```

void edit_heap(void)

{
  long lVar1;
  int index;
  int size;
  long in_FS_OFFSET;
  char input [8];
  long canary;
 
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Index :");
  read(0,input,4);
  index = atoi(input);
  if ((index < 0) || (9 < index)) {
    puts("Out of bound!");
                    /* WARNING: Subroutine does not return */
    _exit(0);
  }
  if (*(long *)(heaparray + (long)index * 8) == 0) {
    puts("No such heap !");
  }
  else {
    printf("Size of Heap : ");
    read(0,input,8);
    size = atoi(input);
    printf("Content of heap : ");
    read_input(*(undefined8 *)(heaparray + (long)index * 8),(long)size,(long)size);
    puts("Done !");
  }
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

Here we can see it prompts us for an index to a chunk, a size for the chunk, and allows us to scan that much data into the chunk. However there is no check to see if the size of our new input is bigger than the size of the chunk itself. With this we have a heap overflow bug:

```
void delete_heap(void)

{
  int index;
  long in_FS_OFFSET;
  char input [8];
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  printf("Index :");
  read(0,input,4);
  index = atoi(input);
  if ((index < 0) || (9 < index)) {
    puts("Out of bound!");
                    /* WARNING: Subroutine does not return */
    _exit(0);
  }
  if (*(long *)(heaparray + (long)index * 8) == 0) {
    puts("No such heap !");
  }
  else {
    free(*(void **)(heaparray + (long)index * 8));
    *(undefined8 *)(heaparray + (long)index * 8) = 0;
    puts("Done !");
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

We can see that `delete_heap` frees the pointer for the index we give it (first it performs some checks on the index). After that it clears out the pointer. No UAF here.

## Exploitation

So we have a buffer overflow bug. We will leverage this bug to write a value to `magic` big enough to let us get the flag. We will do this using an unsorted bin attack, which will allow us to write a large integer value.

#### Unsorted Bin Attack

The Unsorted Bin contains just a single bin. All chunks are first placed in this bin, before being moved to the other bins. The unsorted bin is a doub