# zctf 2016 note2

Let's see what we are dealing with:

```
$    file note2
note2: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.24, BuildID[sha1]=46dca2e49f923813b316f12858e7e0f42e4a82c3, stripped
$    pwn checksec note2
[*] '/home/guyinatuxedo/Desktop/zctf/note2'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    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>.
$    ./note2
Input your name:
15935728
Input your address:
15935728
1.New note
2.Show  note
3.Edit note
4.Delete note
5.Quit
option--->>
```

So we are dealing with a `64` bit elf binary, with a stack canary and NX (but no RELRO). We also see that we are given a libc version `2.23` (I'm not sure if that is the one originally associated with the challenge, but that is what I will use here). When we run the binary, it prompts us for a name and an address. After that we get a menu where we can make a not, show a not, edit a note, and delete a note.

### Reversing

Looking through the list of functions in Ghidra (or checking the xreferences to certain strings and tracing back where the functions that contain those strings are called) we find this function which acts as the menu:

```
void menu(void)

{
  undefined4 uVar1;
 
  setvbuf(stdin,(char *)0x0,2,0);
  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stderr,(char *)0x0,2,0);
  alarm(0x3c);
  puts("Input your name:");
  callRead(&name,0x40,10);
  puts("Input your address:");
  callRead(&address,0x60,10);
LAB_0040101c:
  uVar1 = printMenu();
  switch(uVar1) {
  case 1:
    allocateChunk();
    goto LAB_0040101c;
  case 2:
    showChunk();
    goto LAB_0040101c;
  case 3:
    editChunk();
    goto LAB_0040101c;
  case 4:
    freeChunk();
    goto LAB_0040101c;
  case 5:
    break;
  case 6:
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  puts("Bye~");
                    /* WARNING: Subroutine does not return */
  exit(0);
}
```

So we can see, it prompts us to scan in a name and an address (which correlate to the bss addresses `0x6020e0` and `0x602180`). Let's take a look at the `allocateChunk` function:

```
void allocateChunk(void)

{
  uint size;
  void *ptr;
  ulong uVar1;
 
  if (count < 4) {
    puts("Input the length of the note content:(less than 128)");
    size = getInt();
    if (size < 0x81) {
      ptr = malloc((ulong)size);
      puts("Input the note content:");
      callRead(ptr,(ulong)size,10,(ulong)size);
      FUN_00400b10(ptr);
      *(void **)(&pointers + (ulong)count * 8) = ptr;
      *(ulong *)(&sizes + (ulong)count * 8) = (ulong)size;
      uVar1 = (ulong)count;
      count = count + 1;
      printf("note add success, the id is %d\n",uVar1);
    }
    else {
      puts("Too long");
    }
  }
  else {
    puts("note lists are full");
  }
  return;
}
```

So we can see that we get to specify the size of the chunk that is malloced, however it can't be greater than `0x81` bytes. After that It will allow us to scan in data into that buffer. After that it will save the pointer to the malloced chunk in the array `pointers` (stored in the bss address `0x602120`). It also stores the size of the chunk in the bss array `sizes` at `0x602140`. We also see that it keeps a count of how many chunks have been allocated with the bss integer `count` at `0x602160` (and we can only allocate `4` chunks). Also through trial and error, we see that with this we get a heap overflow bug. Next we take a look at the `showChunk` function:

```
void showChunk(void)

{
  int iVar1;
 
  puts("Input the id of the note:");
  iVar1 = getInt();
  if (((-1 < iVar1) && (iVar1 < 4)) && (*(long *)(&pointers + (long)iVar1 * 8) != 0)) {
    printf("Content is %s\n",*(undefined8 *)(&pointers + (long)iVar1 * 8));
  }
  return;
}
```

So we can see here, it prompts us for an index for the `pointers` array. If it passed a check, it will print the contents of the chunk using `printf`. Next up we have the `editChunk` function:

```
void editChunk(void)

{
  char *__src;
  long lVar1;
  undefined8 *puVar2;
  int iVar3;
  size_t sVar4;
  long in_FS_OFFSET;
  char local_100 [128];
  undefined8 *local_80;
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  if (count == 0) {
    puts("Please add a note!");
  }
  else {
    puts("Input the id of the note:");
    iVar3 = getInt();
    if ((-1 < iVar3) && (iVar3 < 4)) {
      __src = *(char **)(&pointers + (long)iVar3 * 8);
      lVar1 = *(long *)(&sizes + (long)iVar3 * 8);
      if (__src == (char *)0x0) {
        puts("note has been deleted");
      }
      else {
        puts("do you want to overwrite or append?[1.overwrite/2.append]");
        iVar3 = getInt();
        if ((iVar3 == 1) || (iVar3 == 2)) {
          if (iVar3 == 1) {
            local_100[0] = '\0';
          }
          else {
            strcpy(local_100,__src);
          }
          local_80 = (undefined8 *)malloc(0xa0);
          *local_80 = 0x6f4377654e656854;
          local_80[1] = 0x3a73746e65746e;
          printf((char *)local_80);
          callRead((long)local_80 + 0xf,0x90,10);
          FUN_00400b10((long)local_80 + 0xf);
          puVar2 = local_80;
          sVar4 = strlen(local_100);
          *(undefined *)((lVar1 - sVar4) + 0xe + (long)puVar2) = 0;
          strncat(local_100,(char *)((long)local_80 + 0xf),0xffffffffffffffff);
          strcpy(__src,local_100);
          free(local_80);
          puts("Edit note success!");
        }
        else {
          puts("Error choice!");
        }
      }
    }
  }
  if (canary == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
```

With this function, I didn't really reverse it. Through trial and error, I see that it allows us to edit chunks. I also noticed that there appears to be another bug in this function, however with everything else I didn't need it to get a shell (I was a bit tired from work when I solved this challenge). Next up we have the `freeChunk` function.

```
void freeChunk(void)

{
  int iVar1;
 
  puts("Input the id of the note:");
  iVar1 = getInt();
  if (((-1 < iVar1) && (iVar1 < 4)) && (*(long *)(&pointers + (long)iVar1 * 8) != 0)) {
    free(*(void **)(&pointers + (long)iVar1 * 8));
    *(undefi