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.
Invincea-X 6.1.3-24058 (Dell Protected Workspace)
8.1 - CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
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
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
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;
2016-12-12 - Vendor Disclosure
2017-06-30 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.