Talos Vulnerability Report

TALOS-2016-0256

Invincea-X SboxDrv.sys Version Number Query Local Privilege Escalation Vulnerability

June 30, 2017
CVE Number

CVE-2016-9038

Summary

An exploitable double fetch vulnerability exists in the SboxDrv.sys driver functionality of Invincea-X 6.1.3-24058. A specially crafted input buffer and race condition can result in kernel memory corruption, which could result in privilege escalation. An attacker needs to execute a special application locally to trigger this vulnerability.

Tested Versions

Invincea-X 6.1.3-24058 (Dell Protected Workspace)

Product URLs

https://www.invincea.com/solution-overview/

CVSSv3 Score

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

Details

This vulnerability is present in the SboxDrv.sys driver which is a part of Invincea-X (Dell Protected Workspace).This product provides sandbox functionality for Windows environments. Because of weak permissions set on the driver any malicious application can communicate with driver. The application can also provide pointer value that is double fetched in the kernel, allowing an attacker to cause a race condition resulting in memory corruption which can lead to local privilege escalation. Diving into the details we need to start with permission sets on device created by vulnerable driver. Vectors of attacks are definitely increased due to the weak permissions set on the ‘\Device\SandboxDriverApi’ device created by the SboxDrv.sys driver which gives group Everyone full access to this device.

accesschk.exe -o \Device\SandboxDriverApi
\Device\SandboxDriverApi
  Type: Device
  RW Everyone
  RW NT AUTHORITY\SYSTEM
  RW BUILTIN\Administrators
  R  NT AUTHORITY\RESTRICTED

The driver handles a few IOCTLs codes but one of them (0x222007) is especially rich and uses the first DWORD in the input buffer to decide what particular function is executed. Let’s investigate the vulnerable function which is launched when first DWORD in input buffer is set to 0x12340001:

.text:004014B0 ; signed int __stdcall sub_4014B0(int a1, DWORD inputBuffer)
.text:004014B0 sub_4014B0      proc near               ; DATA XREF:    
sub_423070+105o
.text:004014B0
.text:004014B0 a1              = dword ptr  8
.text:004014B0 inputBuffer     = dword ptr  0Ch
.text:004014B0
.text:004014B0                 push    ebp
.text:004014B1                 mov     ebp, esp
.text:004014B3                 push    edi
.text:004014B4                 mov     edi, [ebp+inputBuffer]
.text:004014B7                 mov     edx, [edi+8]
.text:004014BA                 test    edx, edx
.text:004014BC                 jnz     short loc_4014C8
.text:004014BE                 mov     eax, 0C000000Dh
.text:004014C3                 pop     edi
.text:004014C4                 pop     ebp
.text:004014C5                 retn    8
.text:004014C8 ;    
---------------------------------------------------------------------------
.text:004014C8
.text:004014C8 loc_4014C8:                             ; CODE XREF: sub_4014B0+Cj
.text:004014C8                 mov     eax, ver_string
.text:004014CD                 push    esi
.text:004014CE                 lea     esi, [eax+2]
.text:004014D1
.text:004014D1 loc_4014D1:                             ; CODE XREF: sub_4014B0+2Aj
.text:004014D1                 mov     cx, [eax]
.text:004014D4                 add     eax, 2
.text:004014D7                 test    cx, cx
.text:004014DA                 jnz     short loc_4014D1
.text:004014DC                 sub     eax, esi
.text:004014DE                 sar     eax, 1
.text:004014E0                 push    2               ; Alignment
.text:004014E2                 lea     esi, [eax+eax+2]
.text:004014E6                 push    esi             ; Length
.text:004014E7                 push    edx             ; Address
.text:004014E8                 call    ds:ProbeForWrite
.text:004014EE                 mov     eax, ver_string
.text:004014F3                 mov     ecx, [edi+8]
.text:004014F6                 push    esi             ; size_t
.text:004014F7                 push    eax             ; void *
.text:004014F8                 push    ecx             ; void *
.text:004014F9                 call    memcpy
.text:004014FE                 add     esp, 0Ch
.text:00401501                 pop     esi
.text:00401502                 xor     eax, eax
.text:00401504                 pop     edi
.text:00401505                 pop     ebp
.text:00401506                 retn    8
.text:00401506 sub_4014B0      endp

At address 004014B4 we see that inputBuffer pointer gets put into the edi register and its later also used from this register. Next at 004014B7 a pointer specified by user at offset +8 in inputBuffer is moved to edx. The intended purpose of this pointer is to hold the version of the sandbox driver. We see at address 004014E8 a very important check is done on the edx value using ProbeForWrite before a copy operation is made to this buffer. However, a double fetch vulnerability appears at 004014F3 where the buffer pointer value to which driver version should be copied is again read from inputBuffer (edi + 8) instead of using the checked pointer value kept in edx. This vulnerability opens the possibility for race condition where a malicious application changes the pointer value between ProbeForWrite and its usage in memcpy. Finally that situation will lead to an arbitrary write in kernel address space.

Pseudo-code presenting vulnerable code:

signed int __stdcall sub_4014B0(int a1, struct_inputBuffer *inputBuffer)

  void *inVerBufferLocalPtr; // edx@1
  unsigned int v4; // esi@3

  inVerBufferLocalPtr = inputBuffer->inVerBuffer;
  if ( !inVerBufferLocalPtr )
	return 0xC000000D;
  v4 = 2 * wcslen((const unsigned __int16 *)ver_string) + 2;
  ProbeForWrite(inVerBufferLocalPtr, v4, 2u);
  memcpy(inputBuffer->inVerBuffer, ver_string, v4);
  return 0;

Timeline

2016-12-12 - Vendor Disclosure
2017-06-30 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.