# Csaw 2019 traveller

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

```
$    file traveller
traveller: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b551cbb805a21e18393c3816ffd28dfb11b1ff1e, with debug_info, not stripped
$    pwn checksec traveller
[*] '/Hackery/pod/modules/33-custom_misc_heap/csaw19_traveller/traveller'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
$    ./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>.
$    ./traveller

Hello! Welcome to trip management system.
0x7fffcb8d8a0c

Choose an option:

1. Add a trip
2. Change a trip
3. Delete a trip
4. Check a trip
>
```

So looking at this, we are dealing with a `64` bit binary with `NX`. We can see that we are dealing with `libc-2.23.so`. When we run the binary we get what looks like a stack infoleak, and we see a menu.

## Reversing

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

```
int main(int argc)

{
  uint input;
  int argcCpy;
  char choiceInput [4];
  uint choice_num;
 
  argcCpy = argc;
  puts("\nHello! Welcome to trip management system. ");
  printf("%p \n",&argcCpy);
  puts("\nChoose an option: ");
  do {
    while( true ) {
      while( true ) {
        puts("\n1. Add a trip ");
        puts("2. Change a trip ");
        puts("3. Delete a trip ");
        puts("4. Check a trip ");
        printf("> ");
        fflush(stdout);
        fgets(choiceInput,4,stdin);
        input = atoi(choiceInput);
        if (input != 2) break;
        change();
      }
      if (input < 3) break;
      if (input == 3) {
        delete();
      }
      else {
        if (input == 4) {
          check();
        }
      }
    }
    if (input == 1) {
      add();
    }
  } while( true );
}
```

So it is essentially just a menu, allowing us to `add`, `change`, `delete`, and `check` (also we get a stack infoleak):

```
void add(void)

{
  int iVar1;
  trip *ptr;
  ulong size;
  ulong uVar2;
  char *pcVar3;
  long lVar4;
  char choice [4];
  int choice_num;
  trip *newTrip;
 
  if (tIndex != 7) {
    puts("Adding new trips...");
    ptr = (trip *)malloc(0x10);
    puts("Choose a Distance: ");
    puts("1. 0x80 ");
    puts("2. 0x110 ");
    puts("3. 0x128 ");
    puts("4. 0x150 ");
    puts("5. 0x200 ");
    printf("> ");
    fgets(choice,4,stdin);
    iVar1 = atoi(choice);
    switch(iVar1) {
    default:
      puts("Can\'t you count?");
      return;
    case 1:
      size = strtoul("0x80",(char **)0x0,0);
      ptr->distance = size;
      pcVar3 = (char *)malloc(ptr->distance);
      ptr->destination = pcVar3;
      printf("Destination: ");
      fgets(ptr->destination,(int)ptr->distance,stdin);
      break;
    case 2:
      uVar2 = strtoul("0x110",(char **)0x0,0);
      ptr->distance = uVar2;
      pcVar3 = (char *)malloc(ptr->distance);
      ptr->destination = pcVar3;
      printf("Destination: ");
      fgets(ptr->destination,(int)ptr->distance,stdin);
      break;
    case 3:
      uVar2 = strtoul("0x128",(char **)0x0,0);
      ptr->distance = uVar2;
      pcVar3 = (char *)malloc(ptr->distance);
      ptr->destination = pcVar3;
      printf("Destination: ");
      fgets(ptr->destination,(int)ptr->distance,stdin);
      break;
    case 4:
      uVar2 = strtoul("0x150",(char **)0x0,0);
      ptr->distance = uVar2;
      pcVar3 = (char *)malloc(ptr->distance);
      ptr->destination = pcVar3;
      printf("Destination: ");
      fgets(ptr->destination,(int)ptr->distance,stdin);
      break;
    case 5:
      uVar2 = strtoul("0x200",(char **)0x0,0);
      ptr->distance = uVar2;
      pcVar3 = (char *)malloc(ptr->distance);
      ptr->destination = pcVar3;
      printf("Destination: ");
      fgets(ptr->destination,(int)ptr->distance,stdin);
    }
    printf("Trip %lu added.\n",(ulong)(uint)tIndex);
    lVar4 = (long)tIndex;
    tIndex = tIndex + 1;
    trips[lVar4] = ptr;
    return;
  }
  puts("Cannot add more trips.");
                    /* WARNING: Subroutine does not return */
  exit(0);
}
```

So for the `add` function, it prompts us for a chunk size of either `0x80/0x110/0x128/0x150/0x200`. However this isn't the only chunk that is malloced. There is a `0x10` chunk, which contains a ptr to the new chunk, and the size. This ptr is stored in the bss variable `trips`, with the count for the number of chunks being stored in `tIndex`. In addition to that, it allows us to scan in data into the chunk whose size we have some control over. We can see that the heap structure looks like this:

```
0x0:    ptr to trip chunk
0x8:    size of trip chunk

trip chunk
```

Next up we have `change`:

```
void change(void)

{
  ulong index;
  ssize_t bytesRead;
  char buf [20];
  ssize_t bytes_read;
  trip *oldTrip;
  ssize_t choice;
  trip *ptr;
 
  printf("Update trip: ");
  fgets(buf,0x14,stdin);
  index = strtoul(buf,(char **)0x0,0);
  if ((long)index < (long)tIndex) {
    ptr = trips[index];
    bytesRead = read(0,ptr->destination,ptr->distance);
    ptr->destination[bytesRead] = '\0';
  }
  else {
    puts("No upcoming trip to update.");
  }
  return;
}
```

So we can see that it allows us to specify an index to `trips`, and scan in data into the trip chunk for that index. We can see that there are two bugs here. It checks to make sure that the index we provide is not larger than `tIndex` (the count of the number of trip chunks), however there is nothing stopping us from picking an index like `-5` and referencing something before the start of the ptr array. This index check bug we see in a few different places throughout this binary, however I didn't really use it. The second bug we can see is a null byte overflow:

```
    bytesRead = read(0,ptr->destination,ptr->distance);
    ptr->destination[bytesRead] = '\0';
```

Next up we have the `delte` function:

```
void delete(void)

{
  trip *__ptr;
  ulong index;
  char buf [20];
  trip *tp;
  ssize_t i;
 
  printf("Which trip you want to delete: ");
  fgets(buf,0x14,stdin);
  index = strtoul(buf,(char **)0x0,0);
  if ((long)index < (long)tIndex) {
    __ptr = trips[index];
    if (0 < tIndex) {
      trips[index] = trips[(long)(tIndex + -1)];
      tIndex = tIndex + -1;
    }
    free(__ptr->destination);
    free(__ptr);
  }
  else {
    puts(