# hackIM Shop

### Reversing

Let's take a look at the binary:
```
$    file challenge
challenge: 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]=fe602c2cb2390d3265f28dc0d284029dc91a2df8, not stripped
$    pwn checksec challenge
[*] '/Hackery/hackIM/store/challenge'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
```

So we are dealing with a `64` bit binary with no PIE or RELRO. When we run the binary, we see that we have the option to add, remove and view books. When we take a look at the main function in Ghidra, we see this:

```
void main(void)

{
  int option;
  ssize_t bytesRead;
  long menInput;
  char menuInput [8];
 
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  do {
    while( true ) {
      menu();
      bytesRead = read(0,menuInput,2);
      if (bytesRead != 0) break;
      perror("Err read option\r\n");
    }
    menInput = atol(menuInput);
    option = (int)menInput;
    if (option == 2) {
      remove_book();
    }
    else {
      if (option == 3) {
        view_books();
      }
      else {
        if (option == 1) {
          add_book();
        }
        else {
          puts("Invalid option");
        }
      }
    }
  } while( true );
}
```

So we can see the main function, it essentially just acts as a menu which launches the `remove_book`, `view_books`, and `add_book` functions. Looking at the `add_book` function we see this:

```
void add_book(void)

{
  void *ptr0;
  ulong __size;
  void *ptr1;
  size_t nameLen;
  size_t nameLen1;
  undefined8 price;
  long in_FS_OFFSET;
  int index;
  long canary;
  long name;
  long name1;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  if (num_books == 0x10) {
    puts("Cart limit reached!");
  }
  else {
    ptr0 = malloc(0x38);
    printf("Book name length: ");
    __size = readint();
    if (__size < 0x100) {
      printf("Book name: ");
      ptr1 = malloc(__size);
      *(void **)((long)ptr0 + 8) = ptr1;
      read(0,*(void **)((long)ptr0 + 8),__size);
      name = *(long *)((long)ptr0 + 8);
      nameLen = strlen(*(char **)((long)ptr0 + 8));
      if (*(char *)((nameLen - 1) + name) == '\n') {
        name1 = *(long *)((long)ptr0 + 8);
        nameLen1 = strlen(*(char **)((long)ptr0 + 8));
        *(undefined *)((nameLen1 - 1) + name1) = 0;
      }
      printf("Book price: ");
      price = readint();
      *(undefined8 *)((long)ptr0 + 0x10) = price;
      index = 0;
      while (*(long *)(books + (long)index * 8) != 0) {
        index = index + 1;
      }
      *(void **)(books + (long)index * 8) = ptr0;
      **(long **)(books + (long)index * 8) = (long)index;
      num_books = num_books + 1;
      strcpy((char *)(*(long *)(books + (long)index * 8) + 0x18),cp_stmt);
    }
    else {
      puts("Too big!");
    }
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

So here is the function which adds books. We can see that it first allocates a chunk of memory with malloc (size `0x38`), then allocates a second chunk of memory with malloc, and the ptr to that is stored in the first chunk of memory at offset `8`. In the second chunk of memory, we get to scan in up to `0xff` bytes of memory (depending on what we give it as a size), and the chunk of memory scales with it. After that it prompts us for the price of the books. Finally it stores the initial pointer in `books` which is the bss address `0x6021a0`, increments the count of books `num_books` (bss address `0x6020e0`), and then copies the string `Copyright NullCon Shop` stored in `cp_stmt` to the first chunk of memory. Also there is a limit of `0xf` on how many books we can have allocated at a time. Reversing out everything, we can see that this is how the data is structured:

Books is a single array of heap pointers:

```
gef➤  x/2g 0x6021a0
0x6021a0 <books>: 0x[PII_REDACTED]603260  0x[PII_REDACTED]6032c0
```

Each book has the following structure:
```
0x0:    Int contains index of book
0x8:    Ptr to name of book
0x10:   len of book name
0x18:   The string ""Copyright NullCon Shop"
```

Which we can see that layout in gdb:
```
gef➤  x/10g 0x6032c0
0x6032c0: 0x[PII_REDACTED]000001  0x[PII_REDACTED]603300
0x6032d0: 0x[PII_REDACTED]000019  0x[PII_REDACTED]706f43
0x6032e0: 0x6f436c6c754e2074  0x0000706f6853206e
0x6032f0: 0x[PII_REDACTED]000000  0x[PII_REDACTED]000031
0x603300: 0x[PII_REDACTED]313437  0x[PII_REDACTED]000000
```

Looking at the `view_books` function, we see this:

```
void view_books(void)

{
  undefined8 uVar1;
  int index;
 
  puts("{");
  puts("\t\"Books\" : [");
  index = 0;
  while (index < 0x10) {
    if (*(long *)(books + (long)index * 8) != 0) {
      uVar1 = **(undefined8 **)(books + (long)index * 8);
      puts("\t\t{");
      printf("\t\t\t\"index\": %ld,\n",uVar1);
      printf("\t\t\t\"name\": \"%s\",\n",*(undefined8 *)(*(long *)(books + (long)index * 8) + 8));
      printf("\t\t\t\"price\": %ld,\n",*(undefined8 *)(*(long *)(books + (long)index * 8) + 0x10));
      printf("\t\t\t\"rights\": \"");
      printf((char *)(*(long *)(books + (long)index * 8) + 0x18));
      puts("\"");
      if (*(long *)(books + (long)(index + 1) * 8) == 0) {
        puts("\t\t}");
      }
      else {
        puts("\t\t},");
      }
    }
    index = index + 1;
  }
  puts("\t]");
  puts("}");
  return;
}
```

Here we can see the `view_books` function, which prints out the various info about the books. We can see that there is a format string bug with `printf((char *)(*(long *)(books + (long)index * 8) + 0x18));`, since it is printing a non static string without a specific format string. However we will need another bug to effectively use it. Looking at the `remove_book` function we see this:

```
void remove_book(void)

{
  ulong index;
 
  printf("Book index: ");
  index = readint();
  if (index < (ulong)num_books) {
    free(*(void **)(*(long *)(books + index * 8) + 8));
    free(*(void **)(books + index * 8));
    num_books = num_books - 1;
  }
  else {
    puts("Invalid index");
  }
  return;
}
```

Here we can see is the `remove_book` function. It checks to see if the book is valid by checking if the index given is larger than the count of currently allocated books `num_books`, which is a bug. However we see that if the check is passed, that it just frees the two pointers for the associated bug, and decrements `num_books`. However after it frees the pointers, it doesn't get rid of them from `books` (or anywhere else), and doesn't directly edit the data stored there (unless free/malloc does), so we have a use after free bug here.

### Infoleak

Since PIE is disabled, we know the addresses of the got table entries. Since RELRO is disabled, we can write to it. Our plan will essentially be to overwrite a pointer that is printed with that of a got table address, and print