# Csaw 2018 AlienVSSamurai

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 aliensVSsamurais
aliensVSsamurais: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=226c2e3531a2eb42de6f75a31e307146d23f990e, not stripped
$    pwn checksec aliensVSsamurais
[*] '/Hackery/pod/modules/custom_misc_heap/csaw18_alienVSsamurai/aliensVSsamurais'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
$    ./aliensVSsamurais
Daimyo, nani o shitaidesu ka?
3
Brood mother, what tasks do we have today.
4
Aliens have taken over the world.....
```

So we are dealing with a `64` bit binary, with the `libc-2.23.so` libc. The binary has a Stack Canary, NX, and PIE (but no relro). When we run the binary we are first prompted with a samurai menu, then an alien menu, and then aliens take over the world.

## Reversing

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

```
undefined8 main(void)

{
  dojo();
  saved_malloc_hook = __malloc_hook;
  saved_free_hook = __free_hook;
  hatchery();
  invasion();
  return 0;
}
```

So we can see it calls three functions, `dojo`, `hatchery`, and `invasion`. After it calls `dojo`, it saves the hooks for malloc and free (which will cause us problems later). Looking at `dojo`, we see that it is a menu with three options.

```
void dojo(void)

{
  ulong task;
  long in_FS_OFFSET;
  char taskInput [24];
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  while( true ) {
    while( true ) {
      puts("Daimyo, nani o shitaidesu ka?");
      fgets(taskInput,0x18,stdin);
      task = strtoul(taskInput,(char **)0x0,0);
      if (task != 2) break;
      seppuku();
    }
    if (task == 3) break;
    if (task == 1) {
      new_samurai();
    }
  }
  if (canary == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
```

We see that option `1` will allow us to allocate a new samurai (essentially allocating a chunk), option `2` will allow us to kill a samurai (essentially freeing the chunk), and option `3` is to move on to the next menu. I didn't find any bugs in these sub functions, or really anything too interesting (plus aliens are cooler, you can guess who I played in Alien VS Predator). So next up we have `hatchery`:

```
void hatchery(void)

{
  ulong task;
  long in_FS_OFFSET;
  char taskInput [24];
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  do {
    while( true ) {
      while( true ) {
        while( true ) {
          puts("Brood mother, what tasks do we have today.");
          fgets(taskInput,0x18,stdin);
          task = strtoul(taskInput,(char **)0x0,0);
          if (task != 2) break;
          consume_alien();
        }
        if (2 < task) break;
        if (task == 1) {
          new_alien();
        }
      }
      if (task != 3) break;
      rename_alien();
    }
  } while (task != 4);
  if (canary == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
```

So with this menu, we can make aliens (`1`), kill aliens (`2`), and rename aliens (`3`). Looking at `new_alien` we see this:

```
void new_alien(void)

{
  ulong nameSize;
  void **alienPtr;
  void *namePtr;
  ssize_t bytesRead;
  long in_FS_OFFSET;
  char nameSizeInput [24];
  long canary;
  long canaryValue;
  long index;
 
  canaryValue = *(long *)(in_FS_OFFSET + 0x28);
  if (alien_index < 200) {
    if (__malloc_hook == saved_malloc_hook) {
      puts("How long is my name?");
      fgets(nameSizeInput,0x18,stdin);
      nameSize = strtoul(nameSizeInput,(char **)0x0,0);
      if (nameSize < 8) {
        puts("Too short!");
      }
      else {
        alienPtr = (void **)malloc(0x10);
        alienPtr[1] = (void *)0x100;
        namePtr = malloc(nameSize);
        *alienPtr = namePtr;
        puts("What is my name?");
        bytesRead = read(0,*alienPtr,nameSize);
        *(undefined *)((long)(int)bytesRead + (long)*alienPtr) = 0;
        index = alien_index * 8;
        alien_index = alien_index + 1;
        *(void ***)(aliens + index) = alienPtr;
      }
    }
    else {
      puts("WHOOOOOOOOOAAAAA");
    }
  }
  else {
    puts("Our mothership is too full!\n We require more overlords.");
  }
  if (canaryValue != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

So we can see how the aliens are made. We can specify the size and content for the name of the alien, but it has to be greater than or equal to `8`. We can see that our aliens are kept in the bss array `aliens` stored at offset `0x3020c0`. We can also see that it keeps track of how many aliens there are with the bss variable `alien_index` at offset `0x3020b0`. We see that the limit on the amount of aliens we can make is `200`. Also before malloc is called, it checks to see if the malloc hook has changed. Since `malloc` is only ever called here and in the samurai menu, unless if we can change the value of `saved_malloc_hook`, attacking the malloc hook isn't feasible. Also we can see the structure of an alien:

```
0x0:    ptr to alien name (chunks size and content we control)
0x8:    0x100 (for how we do things, doesn't really matter too much)
```

Also we can see that there is a null byte overflow bug with how it does it's null termination:
```
        bytesRead = read(0,*alienPtr,nameSize);
        *(undefined *)((long)(int)bytesRead + (long)*alienPtr) = 0;
```

Next up we have:

```
void consume_alien(void)

{
  ulong index;
  long in_FS_OFFSET;
  char indexInput [24];
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  puts("Which alien is unsatisfactory, brood mother?");
  fgets(indexInput,0x18,stdin);
  index = strtoul(indexInput,(char **)0x0,0);
  if (alien_index < index) {
    puts("That alien is too far away >(");
  }
  else {
    if (__free_hook == saved_free_hook) {
      kill_alien(index);
    }
    else {
      puts("Whooooaaaaaaaa");
    }
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;