# popping caps 0

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

```
$ pwn checksec popping_caps
[*] '/Hackery/pod/modules/44-more_tcache/csaw19_popping_caps1/popping_caps'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
$ file popping_caps
popping_caps: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0b94b47318011a[PII_REDACTED]e7aaa0caeda06c79, not stripped
$ ./libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 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 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
$ /popping_caps
Here is system 0x7f8dfb387fd0
You have 7 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:
```

First off we are dealing with libc version `2.27` (so we get to use the tcache). This binary has all of the standard mitigations except for RELRO. When we run it, we get a libc infoleak, and have the ability to malloc, free, and write.

## Reversing

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

```
undefined8 main(void)

{
  ulong choice;
  size_t size;
  long number;
  long idk;
  void *ptr;
  void *ptrCopy;
 
  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stdin,(char *)0x0,2,0);
  setvbuf(stderr,(char *)0x0,2,0);
  printf("Here is system %p\n",system);
  idk = 7;
  ptr = (void *)0x0;
  ptrCopy = (void *)0x0;
  while (idk != 0) {
    printf("You have %llu caps!\n",idk);
    puts("[1] Malloc");
    puts("[2] Free");
    puts("[3] Write");
    puts("[4] Bye");
    puts("Your choice: ");
    choice = read_num();
    if (choice == 2) {
      puts("Whats in a free: ");
      number = read_num();
      free((void *)((long)ptr + number));
      if (ptr == ptrCopy) {
        ptrCopy = (void *)0x0;
      }
    }
    else {
      if (choice < 3) {
        if (choice == 1) {
          puts("How many: ");
          size = read_num();
          ptr = malloc(size);
          ptrCopy = ptr;
        }
      }
      else {
        if (choice == 3) {
          puts("Read me in: ");
          read(0,ptrCopy,8);
        }
        else {
          if (choice == 4) {
            bye();
          }
        }
      }
    }
    puts("BANG!");
    idk = idk + -1;
  }
  bye();
  return 0;
}
```

So we can see a few things here. First we can allocate a chunk of a particular size, which is then stored in `ptrCopy` and `ptr`. Proceeding that, we can also scan in `0x8` bytes into the address pointed to by `ptrCopy`. Also the free works by us providing an offset to `ptr`, which is then freed. After we free it zeroes out `ptrCopy`, but not `ptr`. So after we free once, we will have to allocate another chunk before we can do another write. Also we don’t see any simple way of getting another infoleak.

Also one other important thing, we only get `7` actions (with an action being a read, write, or free). After that `bye` is run which the program calls `malloc` and `exit`:

```
void bye(void)

{
  fwrite(&DAT_00100d04,1,4,stdout);
  malloc(0x38);
                    /* WARNING: Subroutine does not return */
  exit(0);
}
```

## Exploitation

So for exploiting this code, we will be attacking the tcache. Particularly where the tcache stores the beginning of the various linked lists that makes up the tcache, and the corresponding counts. This is stored in a chunk at the beginning of the heap. For a better understanding of this, let's take a look at it:

```
gef➤  vmmap
Start              End                Offset             Perm Path
0x[PII_REDACTED]37b000 0x[PII_REDACTED]37c000 0x[PII_REDACTED]000000 r-x /home/guyinatuxedo/Desktop/popping/popping_caps
0x[PII_REDACTED]57c000 0x[PII_REDACTED]57d000 0x[PII_REDACTED]001000 rw- /home/guyinatuxedo/Desktop/popping/popping_caps
0x[PII_REDACTED]324000 0x[PII_REDACTED]345000 0x[PII_REDACTED]000000 rw- [heap]
0x00007f1e4b9c3000 0x00007f1e4bbaa000 0x[PII_REDACTED]000000 r-x /home/guyinatuxedo/Desktop/popping/libc.so.6
0x00007f1e4bbaa000 0x00007f1e4bdaa000 0x[PII_REDACTED]1e7000 --- /home/guyinatuxedo/Desktop/popping/libc.so.6
0x00007f1e4bdaa000 0x00007f1e4bdae000 0x[PII_REDACTED]1e7000 r-- /home/guyinatuxedo/Desktop/popping/libc.so.6
0x00007f1e4bdae000 0x00007f1e4bdb0000 0x[PII_REDACTED]1eb000 rw- /home/guyinatuxedo/Desktop/popping/libc.so.6
0x00007f1e4bdb0000 0x00007f1e4bdb4000 0x[PII_REDACTED]000000 rw-
0x00007f1e4bdb4000 0x00007f1e4bddb000 0x[PII_REDACTED]000000 r-x /lib/x86_64-linux-gnu/ld-2.27.so
0x00007f1e4bfd9000 0x00007f1e4bfdb000 0x[PII_REDACTED]000000 rw-
0x00007f1e4bfdb000 0x00007f1e4bfdc000 0x[PII_REDACTED]027000 r-- /lib/x86_64-linux-gnu/ld-2.27.so
0x00007f1e4bfdc000 0x00007f1e4bfdd000 0x[PII_REDACTED]028000 rw- /lib/x86_64-linux-gnu/ld-2.27.so
0x00007f1e4bfdd000 0x00007f1e4bfde000 0x[PII_REDACTED]000000 rw-
0x00007ffc5924c000 0x00007ffc5926d000 0x[PII_REDACTED]000000 rw- [stack]
0x00007ffc593ce000 0x00007ffc593d1000 0x[PII_REDACTED]000000 r-- [vvar]
0x00007ffc593d1000 0x00007ffc593d2000 0x[PII_REDACTED]000000 r-x [vdso]
0xffffffffff600000 0xffffffffff601000 0x[PII_REDACTED]000000 r-x [vsyscall]
gef➤  x/100g 0x[PII_REDACTED]324000
0x[PII_REDACTED]00: 0x0 0x251
0x[PII_REDACTED]10: 0x0 0x0
0x[PII_REDACTED]20: 0x0 0x0
0x[PII_REDACTED]30: 0x0 0x0
0x[PII_REDACTED]40: 0x0 0x0
0x[PII_REDACTED]50: 0x0 0x0
0x[PII_REDACTED]60: 0x0 0x0
0x[PII_REDACTED]70: 0x0 0x0
0x[PII_REDACTED]80: 0x0 0x0
0x[PII_REDACTED]90: 0x0 0x0
0x[PII_REDACTED]a0: 0x0 0x0
0x[PII_REDACTED]b0: 0x0 0x0
0x[PII_REDACTED]c0: 0x0 0x0
0x[PII_REDACTED]d0: 0x0 0x0
0x[PII_REDACTED]e0: 0x0 0x0
0x[PII_REDACTED]f0: 0x0 0x0
0x[PII_REDACTED]00: 0x0 0x0
0x[PII_REDACTED]10: 0x0 0x0
0x[PII_REDACTED]20: 0x0 0x0
0x[PII_REDACTED]30: 0x0 0x0
0x[PII_REDACTED]40: 0x0 0x0
0x[PII_REDACTED]50: 0x0 0x0
0x[PII_REDACTED]60: 0x0 0x0
0x[PII_REDACTED]70: 0x0 0x0
0x[PII_REDACTED]80: 0x0 0x0
0x[PII_REDACTED]90: 0x0 0x0
0x[PII_REDACTED]a0: 0x0 0x0
0x[PII_REDACTED]b0: 0x0 0x0
0x[PII_REDACTED]c0: 0x0 0x0
0x[PII_REDACTED]d0: 0x0 0x0
0x[PII_REDACTED]e0: 0x0 0x0
0x[PII_REDACTED]f0: 0x0 0x0
0x[PII_REDACTED]00: 0x0 0x0
0x[PII_REDACTED]10: 0x0 0x0
0x[PII_REDACTED]20: 0x0 0x0
0x[PII_REDACTED]30: 0x0 0x0
0x[PII_REDACTED]40: 0x0 0x0
0x[PII_REDACTED]50: 0x0 0x91
0x[PII_REDACTED]60: 0x0 0x0
0x[PII_REDACTED]70: 0x0 0x0
0x[PII_REDACTED]80: 0x0 0x0
0x[PII_REDACTED]90: 0x0 0x0
0x[PII_REDACTED]a0: 0x0 0x0
0x[PII_REDACTED]b0: 0x0 0x0
0x[PII_REDACTED]c0: 0x0 0x0
0x[PII_REDACTED]d0: 0x0 0x0
0x[PII_REDACTED]e0: 0x0 0x20d21
0x[PII_REDACTED]f0: 0x0 0x0
0x[PII_REDACTED]00: 0x0 0x0
0x[PII_REDACTED]10: 0x0 0x0
```

So we can see the chunk we were talking about the beginning, with a size of `0x251`. We can also see another chunk we allocated at `0x[PII_REDACTED]50` with the size `0x91`. Let's free it and have it inserted into the tcache:

```
gef➤  x/100g 0x[PII_REDACTED]324000
0x[PII_REDACTED]00: 0x0 0x251
0x[PII_REDACTED]10: 0x[PII_REDACTED]0000 0x0
0x[PII_REDACTED]20: 0x0 0x0
0x[PII_REDACTED]30: 0x0 0x0
0x[PII_REDACTED]40: 0x0 0x0
0x[PII_REDACTED]50: 0x0 0x0
0x[PII_REDACTED]60: