Talos Vulnerability Report

TALOS-2019-0946

Microsoft Media Foundation IMFASFSplitter::Initialize Code Execution Vulnerability

February 11, 2020
CVE Number

CVE-2020-0738

Summary

An exploitable type confusion vulnerability exists in the mfasfsrcsnk.dll of Microsoft Media Foundation 10.0.18362.207. A specially crafted ASF file can cause type confusion, resulting in remote code execution. An attacker needs to provide a malformed file to the victim to trigger the vulnerability.

Tested Versions

Windows 10 - Media Foundation ASF Source and Sink DLL - 10.0.18362.207 (WinBuild.160101.0800) x86

Product URLs

https://docs.microsoft.com/en-us/windows/win32/medfound/microsoft-media-foundation-sdk

CVSSv3 Score

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

CWE

CWE-704: Incorrect Type Conversion or Cast

Details

This vulnerability is present in the Media Foundation MPEG4 dll which is part of the Microsoft Media Foundation framework. The Microsoft Media Foundation is a COM based multimedia framework available in Microsoft Windows since Windows Vista. It provides all sort of functionality related with audio/video operations. A specially crafted ASF file can lead to a type confusion vulnerability and could subequently lead to remote code execution.

To trigger the vulnerability we will use one of the SDK example applications available here : https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/mediafoundation/asfparser.

Our PoC file structure looks as follows:

                   offset:                                                        real size:

                             +-------------------------------------------------+
                             |                                                 |
                         0   |                 Header Object                   |  0x1E
                             |                                                 |
                             |                                                 |
                      0x1E   |           Extended Content Description          |  0x1CE
                             |                                                 |
                             |                                                 |
                             |                                                 |
                     0x1EC   |         Stream Bitrate Properties Object        |  0x26
                             |                                                 |
                             |                                                 |
                             |                                                 |
                     0x212   |             File Properties Object              |  0x68
                             |                                                 |
                             |                                                 |
                             |
                     0x27A   |            Header Extension Object              |  0x2E
                             |     +--------------------------------------+    |
                             |     |                                      |    |
                             |     |                                      |    |
                     0x2A8   |     |  Extended Stream Properties Object   |    |  0x108
                             |     |                                      |    |
                     0x3B0   |     |  Extended Stream Properties Object   |    |  0x108
                             |     |                                      |    |
                     0x4B8   |     |  Extended Stream Properties Object   |    |  0x108
                             |     |                                      |    |
                             |     |                                      |    |
                             |     +--------------------------------------+    |
                             |                                                 |
                             |                                                 |
                             +-------------------------------------------------+

As the ASF file format documentation states : https://go.microsoft.com/fwlink/p/?linkid=31334

To be valid, the Header Object must contain a File Properties Object, a Header Extension Object, and at least one Stream Properties Object.

Our malformed ASF PoC file does not contain the Stream Properties Object but still the pContentInfo->ParseHeader method at asfparser/ASFManager.cpp#L194 returns without error.

Looking inside the IMFASFContentInfo::ParseHeader method, we can notice that is because the second malformed Extended Stream Properties Object at offset 0x3B0 is treated as a Stream Properties Object :

Line 1 	7B5AB2D0
Line 2 	signed int __thiscall CASFStreamPropertiesObjectEx::ReadInternal(_DWORD *this, _DWORD *a2)
Line 3 	{
Line 4 		(...)
Line 5 		  v186 = 0;
Line 6 		  if ( (unsigned __int16)Dst <= 0u )
Line 7 		  {
Line 8 	LABEL_50:
Line 9 			if ( (unsigned __int64)(readObjectSize - v29->currentSize) < *(_QWORD *)&v29->gap4[28] )
Line 10			{
Line 11			  v155 = *(_DWORD *)&v29->gap4[8];
Line 12			  vulnObject = 0;
Line 13			  retCode = (*(int (__thiscall **)(_DWORD, int, int *, int (__stdcall **)(void *)))(*(_DWORD *)v155
Line 14																							  + 28))(// 0x7B5AE710 - ReadPropertiesObject
Line 15						  *(_DWORD *)(*(_DWORD *)v155 + 28),
Line 16						  v155,
Line 17						  ASF_Stream_Properties_Object,
Line 18						  &vulnObject);
Line 19			  if ( retCode >= 0 )
Line 20			  {
Line 21				v158 = (struct_v157 *)v183;
Line 22				v183->vulnObject = vulnObject;	

The crucial issue here seems to be the value of objectSize

					value 	offset  size
QWORD objectSize	B70h	3C0h	8h		

which equals amount of bytes left to the end of the file. A value bigger than file size 0xF20 - 0x3B0 causes a parser error, the same happens for a smaller value.

Further, the ASF Stream Properties object is added to the one of the IMFASFContentInfo class containers via CASFUnknownContainer::InsertCompletedObject method. That container already contains two Extended Stream Properties objects. When the IMFASFContentInfo::ParseHeader method ends successfully, the IMFASFContentInfo object is passed as an argument to the IMFASFSplitter::Initialize method at line asfparser/ASFManager.cpp#L244.

The vulnerable code is located inside the CASFPacketParser::CreateExtensionSystemsList method:

call stack:
CMFASFSplitter::Initialize
	CASFPacketParser::CASFPacketParser
		CASFPacketParser::CreateExtensionSystemsList
		

Line 1 unsigned int __thiscall CASFPacketParser::CreateExtensionSystemsList(int this, int a2)
Line 2 {
Line 3   (...)
Line 4   objectCount = 0;
Line 5   errorCode = (void *)(*(int (__thiscall **)(_DWORD, int, int *, unsigned int *))(*(_DWORD *)objSome
Line 6 																				+ 12))(// 0x7b5ad1c0 - CASFUnknownContainer::GetObjectCount
Line 7 						*(_DWORD *)(*(_DWORD *)objSome + 12),
Line 8 						objSome,
Line 9 						&ASF_Extended_Stream_Properties_Object,
Line 10						&objectCount);
Line 11
Line 12	if ( objectCount )
Line 13	{
Line 14	  for (int i = 0 ; i <  objectCount; i++ )
Line 15	  {
Line 16		errorCode = (void *)(*(int (__thiscall **)(_DWORD, int, int *, unsigned int, struct_vulnBuffer **))(*(_DWORD *)objSome + 16))(// getObject - 0x7b5a1a20
Line 17							  *(_DWORD *)(*(_DWORD *)objSome + 16),
Line 18							  objSome,
Line 19							  &ASF_Extended_Stream_Properties_Object,
Line 20							  v10,
Line 21							  &extendedStreamProperties);
Line 22		if ( (signed int)errorCode < 0 )
Line 23		{
Line 24			//Handle error
Line 25		}
Line 26		else
Line 27		{
Line 28		  _extendedStreamProperties = extendedStreamProperties;
Line 29		  if ( extendedStreamProperties )
Line 30		  {
Line 31			errorCode = 0;
Line 32			streamNumber = extendedStreamProperties->streamNumber;
Line 33			extensionSystemCount = extendedStreamProperties->extensionSystemCount;// XXX : OOB read/access
Line 34			_errorCode = 0;
Line 35			_extensionSystemCount = extensionSystemCount;
Line 36			extensionSystemPayload = objectMalloc(8u);
Line 37			if ( extensionSystemPayload )
Line 38			{
Line 39			  v14 = allocExtensionSystemsPayload(
Line 40					  (int)extensionSystemPayload,
Line 41					  _extensionSystemCount,
Line 42					  (signed int *)&_errorCode);
Line 43			  errorCode = _errorCode;
Line 44			}
Line 45			else
Line 46			{
Line 47			  v14 = 0;
Line 48			}
Line 49			v39 = v14;
Line 50			_errorCode = v14;
Line 51			if ( (signed int)errorCode < 0 )
Line 52			{
Line 53				//Handle error
Line 54			}
Line 55			else if ( v14 )
Line 56			{
Line 57			  
Line 58			  for ( index_1 = 0;index_1 < (unsigned __int16)_extensionSystemCount )
Line 59			  {
Line 60				errorCode = (void *)sub_7B5A0F8B(_extendedStreamProperties, index_1, (int)&a3, (int)&a4, 0, 0);// <--------- b000m!
Line 61
Line 62	(...)			

As we can see in a above code, the objects which are supposed to be ASF_Extended_Stream_Properties_Object are pulled out from a container via method at line 16. In our case the variable objectCount is equal 3 and two first object seems to be valid ASF_Extended_Stream_Properties_Object objects:

7b6739e8 ff5610         call    dword ptr [esi+10h] // getObject
7b6739eb 8bf8           mov     edi, eax
7b6739ed 85ff           test    edi, edi
7b6739ef 0f882a030000   js      mfasfsrcsnk!MFCreateASFStreamingMediaSink+0x4571f (7b673d1f)
7b6739f5 8b75f4         mov     esi, dword ptr [ebp-0Ch]
7b6739f8 85f6           test    esi, esi

0:000> !heap -p -a 0x1694de98
	address 1694de98 found in
	_DPH_HEAP_ROOT @ 16871000
	in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
								16872270:         1694de98              168 -         1694d000             2000
		  ? mfasfsrcsnk+134c
	7c59ab70 verifier!AVrfDebugPageHeapAllocate+0x00000240
	772f8fcb ntdll!RtlDebugAllocateHeap+0x00000039
	7724bb0d ntdll!RtlpAllocateHeap+0x000000ed
	7724b02f ntdll!RtlpAllocateHeapInternal+0x0000022f
	7724adee ntdll!RtlAllocateHeap+0x0000003e
	755a7610 msvcrt!malloc+0x00000090
	7b5bf417 mfasfsrcsnk!DllCanUnloadNow+0x00003897
	7b5aedac mfasfsrcsnk!DllGetClassObject+0x0001143c
	7b5add9e mfasfsrcsnk!DllGetClassObject+0x0001042e
	7b5ad59a mfasfsrcsnk!DllGetClassObject+0x0000fc2a
	7b5a5e59 mfasfsrcsnk!DllGetClassObject+0x000084e9
	7b5b74c5 mfasfsrcsnk!DllGetClassObject+0x00019b55
	002c12c1 AsfReaderHeap!CASFReader::CreateASFContentInfo+0x00000101 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 111]
	002c1145 AsfReaderHeap!CASFReader::OpenASFFile+0x00000055 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 52]
	002c1f71 AsfReaderHeap!fuzzme+0x00000031 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 249]
	002c20c0 AsfReaderHeap!main+0x000000e0 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 301]
	002c3987 AsfReaderHeap!__scrt_common_main_seh+0x000000fa [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
	76d16359 KERNEL32!BaseThreadInitThunk+0x00000019
	77277b74 ntdll!__RtlUserThreadStart+0x0000002f
	77277b44 ntdll!_RtlUserThreadStart+0x0000001b
	
	second 
	
0:000> !heap -p -a 0x1f544e98	
	address 1f544e98 found in
	_DPH_HEAP_ROOT @ 16871000
	in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
								16873e04:         1f544e98              168 -         1f544000             2000
		  ? mfasfsrcsnk+134c
	7c59ab70 verifier!AVrfDebugPageHeapAllocate+0x00000240
	772f8fcb ntdll!RtlDebugAllocateHeap+0x00000039
	7724bb0d ntdll!RtlpAllocateHeap+0x000000ed
	7724b02f ntdll!RtlpAllocateHeapInternal+0x0000022f
	7724adee ntdll!RtlAllocateHeap+0x0000003e
	755a7610 msvcrt!malloc+0x00000090
	7b5bf417 mfasfsrcsnk!DllCanUnloadNow+0x00003897
	7b5aedac mfasfsrcsnk!DllGetClassObject+0x0001143c
	7b5add9e mfasfsrcsnk!DllGetClassObject+0x0001042e
	7b5ad59a mfasfsrcsnk!DllGetClassObject+0x0000fc2a
	7b5a5e59 mfasfsrcsnk!DllGetClassObject+0x000084e9
	7b5b74c5 mfasfsrcsnk!DllGetClassObject+0x00019b55
	002c12c1 AsfReaderHeap!CASFReader::CreateASFContentInfo+0x00000101 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 111]
	002c1145 AsfReaderHeap!CASFReader::OpenASFFile+0x00000055 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 52]
	002c1f71 AsfReaderHeap!fuzzme+0x00000031 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 249]
	002c20c0 AsfReaderHeap!main+0x000000e0 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 301]
	002c3987 AsfReaderHeap!__scrt_common_main_seh+0x000000fa [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
	76d16359 KERNEL32!BaseThreadInitThunk+0x00000019
	77277b74 ntdll!__RtlUserThreadStart+0x0000002f
	77277b44 ntdll!_RtlUserThreadStart+0x0000001b		

and the last one is different from the others:

		    _DPH_HEAP_ROOT @ 16871000
in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                            16873a28:         1f56af70               90 -         1f56a000             2000
      ? mfasfsrcsnk+1694
7c59ab70 verifier!AVrfDebugPageHeapAllocate+0x00000240
772f8fcb ntdll!RtlDebugAllocateHeap+0x00000039
7724bb0d ntdll!RtlpAllocateHeap+0x000000ed
7724b02f ntdll!RtlpAllocateHeapInternal+0x0000022f
7724adee ntdll!RtlAllocateHeap+0x0000003e
755a7610 msvcrt!malloc+0x00000090
7b5bf417 mfasfsrcsnk!DllCanUnloadNow+0x00003897
7b5aef5e mfasfsrcsnk!DllGetClassObject+0x000115ee
7b5cf01d mfasfsrcsnk!DllCanUnloadNow+0x0001349d
7b5ba3f8 mfasfsrcsnk!DllGetClassObject+0x0001ca88
7b5ad7b3 mfasfsrcsnk!DllGetClassObject+0x0000fe43
7b5a5e59 mfasfsrcsnk!DllGetClassObject+0x000084e9
7b5b74c5 mfasfsrcsnk!DllGetClassObject+0x00019b55
002c12c1 AsfReaderHeap!CASFReader::CreateASFContentInfo+0x00000101 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 111]
002c1145 AsfReaderHeap!CASFReader::OpenASFFile+0x00000055 [t:\projects\cpp\wmf\wmf\wmf\casfreader.cpp @ 52]
002c1f71 AsfReaderHeap!fuzzme+0x00000031 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 249]
002c20c0 AsfReaderHeap!main+0x000000e0 [t:\projects\cpp\wmf\wmf\wmf\wmf.cpp @ 301]
002c3987 AsfReaderHeap!__scrt_common_main_seh+0x000000fa [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
76d16359 KERNEL32!BaseThreadInitThunk+0x00000019
77277b74 ntdll!__RtlUserThreadStart+0x0000002f
77277b44 ntdll!_RtlUserThreadStart+0x0000001b

when we check one of the functions related with its allocation call stack we can see:

Line 1 	int __stdcall sub_7B5AE710(int a1, void *Buf2, int a3)
Line 2 	{
Line 3 		(...)
Line 4 		if ( !memcmp(ASF_Stream_Properties_Object, Buf2, 0x10u) )
Line 5 		{
Line 6 		  vulnObject = (char *)objectMalloc(0x90u);// XXX fixed alloc
Line 7 		  if ( !vulnObject )
Line 8 			return 0x8007000E;
Line 9 		  _vulnObject = (_DWORD *)vulnObjectContructor(vulnObject);
Line 10		  __vulnObject = _vulnObject;
Line 11		  if ( !_vulnObject )
Line 12			return 0x8007000E;
Line 13		  v168 = (*(int (__thiscall **)(_DWORD, _DWORD *, PDWORD *, int))*_vulnObject)(// 0x7b5af870 - GUID comp
Line 14				   *(_DWORD *)*_vulnObject,
Line 15				   _vulnObject,
Line 16				   &dword_7B589140,
Line 17				   a3);		

The ASF_Stream_Properties_Object object has smaller size and is being here treated as an ASF_Extended_Stream_Properties_Object object. That object type confusion leads the function CASFPacketParser::CreateExtensionSystemsList at line 33 to read a value out of the object’s bounds. Later based on this value, the loop at lines 58-62 is controlled. Depending on the attacker’s ability to control the heap above, the type confusion can lead to a memory leak or memory corruption which can allow an attacker to achieve remote code execution.

Crash Information

(58d4.3018): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00d069d4 ecx=abababab edx=00000000 esi=abababab edi=00000000
eip=7b5a0770 esp=010ffc08 ebp=010ffc14 iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010282
mfasfsrcsnk!DllGetClassObject+0x2e00:
7b5a0770 8b4e04          mov     ecx,dword ptr [esi+4] ds:002b:abababaf=????????
0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


KEY_VALUES_STRING: 1

	Key  : AV.Fault
	Value: Read

	Key  : Analysis.CPU.Sec
	Value: 0

	Key  : Analysis.DebugAnalysisProvider.CPP
	Value: Create: 8007007e on DESKTOP-E4N8506

	Key  : Analysis.DebugData
	Value: CreateObject

	Key  : Analysis.DebugModel
	Value: CreateObject

	Key  : Analysis.Elapsed.Sec
	Value: 7

	Key  : Analysis.Memory.CommitPeak.Mb
	Value: 58

	Key  : Analysis.System
	Value: CreateObject

	Key  : Timeline.OS.Boot.DeltaSec
	Value: 1653226

	Key  : Timeline.Process.Start.DeltaSec
	Value: 23


EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 7b5a0770 (mfasfsrcsnk!DllGetClassObject+0x00002e00)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: abababaf
Attempt to read from address abababaf

FAULTING_THREAD:  00003018

PROCESS_NAME:  WMF.exe

READ_ADDRESS:  abababaf 

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

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  abababaf

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
010ffc14 7b5a0fbb 00000000 00d06948 010ffc66 mfasfsrcsnk!DllGetClassObject+0x2e00
010ffc2c 7b673a77 00000000 010ffc54 010ffc64 mfasfsrcsnk!DllGetClassObject+0x364b
010ffc98 7b672400 00d03fc0 00d042d0 00000000 mfasfsrcsnk!MFCreateASFStreamingMediaSink+0x45477
010ffcb4 7b6836bf 00d03fc0 010ffcd0 00000000 mfasfsrcsnk!MFCreateASFStreamingMediaSink+0x43e00
010ffcd4 7b60e1f0 00d042d0 00d06ab0 011f7020 mfasfsrcsnk!MFCreateASFStreamingMediaSink+0x550bf
010ffd1c 00c313d3 00d06a50 00d03ec0 010ffdd0 mfasfsrcsnk!MFCreateASFStreamPrioritization+0x20f0
010ffd50 00c31165 00d03a78 010ffdd8 010ffdd0 WMF!CASFReader::CreateASFSplitter+0x93
010ffd70 00c31f71 011f75d8 010ffdb8 6b369ff8 WMF!CASFReader::OpenASFFile+0x75
010ffdfc 00c320c0 011f75d8 12901598 011f0000 WMF!fuzzme+0x31
010ffe50 00c33987 00000002 011f7020 011f61d0 WMF!main+0xe0
010ffe98 76d16359 00ec5000 76d16340 010fff04 WMF!__scrt_common_main_seh+0xfa
010ffea8 77277b74 00ec5000 22868102 00000000 KERNEL32!BaseThreadInitThunk+0x19
010fff04 77277b44 ffffffff 77298f27 00000000 ntdll!__RtlUserThreadStart+0x2f
010fff14 00000000 00c33a0f 00ec5000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s ; .cxr ; kb

SYMBOL_NAME:  mfasfsrcsnk!DllGetClassObject+2e00

MODULE_NAME: mfasfsrcsnk

IMAGE_NAME:  mfasfsrcsnk.dll

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_c0000005_mfasfsrcsnk.dll!DllGetClassObject

OS_VERSION:  10.0.18362.239

BUILDLAB_STR:  19h1_release_svc_prod1

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 10

FAILURE_ID_HASH:  {6721a602-9996-8910-8d1c-08e5b792ff24}

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

0:000> lmv a eip
Browse full module list
start    end        module name
7b580000 7b6b8000   mfasfsrcsnk   (export symbols)       C:\WINDOWS\SYSTEM32\mfasfsrcsnk.dll
	Loaded symbol image file: C:\WINDOWS\SYSTEM32\mfasfsrcsnk.dll
	Image path: C:\WINDOWS\SysWOW64\mfasfsrcsnk.dll
	Image name: mfasfsrcsnk.dll
	Browse all global symbols  functions  data
	Image was built with /Brepro flag.
	Timestamp:        D199DF63 (This is a reproducible build file hash, not a timestamp)
	CheckSum:         00136EB8
	ImageSize:        00138000
	File version:     10.0.18362.207
	Product version:  10.0.18362.207
	File flags:       0 (Mask 3F)
	File OS:          40004 NT Win32
	File type:        2.0 Dll
	File date:        00000000.00000000
	Translations:     0409.04b0
	Information from resource tables:
		CompanyName:      Microsoft Corporation
		ProductName:      MicrosoftÆ WindowsÆ Operating System
		InternalName:     Media Foundation ASF Source and Sink DLL
		OriginalFilename: mfasfsrcsnk.dll
		ProductVersion:   10.0.18362.207
		FileVersion:      10.0.18362.207 (WinBuild.160101.0800)
		FileDescription:  Media Foundation ASF Source and Sink DLL
		LegalCopyright:   © Microsoft Corporation. All rights reserved.

Timeline

2019-10-31 - Vendor Disclosure
2019-11-06 - Vendor requested additional trigger input files
2019-11-18 - Talos provided additional trigger input file to vendor
2020-01-02 - 60+ day follow up
2020-01-06 - Vendor provided patch/release timeline
2020-02-10 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.