Talos Vulnerability Report

TALOS-2019-0912

Microsoft Media Foundation CMP4MetadataHandler AddQTMetadata Code Execution Vulnerability

November 12, 2019
CVE Number

CVE-2019-1430

Summary

An exploitable use-after-free vulnerability exists in the mfmp4srcsnk.dll of Microsoft Media Foundation. A specially crafted QuickTime file can cause a Use-After-Free, resulting in a remote code execution. An attacker needs to provide a malformed file to the victim to trigger the vulnerability.

Tested Versions

Windows 10 - Media Foundation MPEG4 Source and Sink DLL - 10.0.18362.207 (WinBuild.160101.0800) x86/x64 Windows Media Player 12.0.18362.1 Microsoft Edge 44.18362.267.0

Product URLs

https://docs.microsoft.com/pl-pl/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-416: Use After Free

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 QuickTime file can lead to a use-after-free vulnerability which can result in remote code execution.

Attaching debugger to the Windows Media Player and loading(drag&drop) the malformed MOV file we end up in the following context:

(7a38.7e04): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=18004ec8 ebx=18004f18 ecx=161fbee8 edx=00100000 esi=00000001 edi=00000000
eip=2dad60d9 esp=0303af08 ebp=0303af20 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata+0x1a:
2dad60d9 8b30            mov     esi,dword ptr [eax]  ds:002b:18004ec8=????????

0:000> !heap -p -a 18004ec8
	address 18004ec8 found in
	_DPH_HEAP_ROOT @ 7ff1000
	in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
								   1814209c:         18004000             2000
	7c1fadc2 verifier!AVrfDebugPageHeapFree+0x000000c2
	774c97a3 ntdll!RtlDebugFreeHeap+0x0000003e
	7741dd1e ntdll!RtlpFreeHeap+0x000000ce
	77466bfb ntdll!RtlpFreeHeapInternal+0x00000783
	7741dbf6 ntdll!RtlFreeHeap+0x00000046
	771f7409 msvcrt!free+0x00000069
	2db980c9 mfmp4srcsnk!CQTMetadataMapAtom::`vector deleting destructor'+0x00000019
	2dae79e0 mfmp4srcsnk!CAggUnknown::NonDelegatingRelease+0x00000040
	2dabd4fc mfmp4srcsnk!CEnumAtoms::Release+0x0000001c
	2dad5be5 mfmp4srcsnk!CQTAtom::~CQTAtom+0x00000069
	2db0615a mfmp4srcsnk!CMP4MetadataAtom::~CMP4MetadataAtom+0x0000015c
	2db05c6d mfmp4srcsnk!CMP4MetadataAtom::`vector deleting destructor'+0x0000000d
	2dae79e0 mfmp4srcsnk!CAggUnknown::NonDelegatingRelease+0x00000040
	2dadd09f mfmp4srcsnk!CQTAtom::Release+0x0000001f
	2db29d5d mfmp4srcsnk!CQTAtom::CreateTypedAtom+0x000453ed
	2dae693e mfmp4srcsnk!CQTMovie::CreateChildAtom+0x0000034e
	2dae4559 mfmp4srcsnk!CQTAtom::ScanChildrenInBuffer+0x00000249
	2dae42a8 mfmp4srcsnk!CQTAtom::ScanChildren+0x000000c8
	2dad5d78 mfmp4srcsnk!CQTMovie::CreateQTMovie+0x00000098
	2dad4124 mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x000001c6
	2dad39a6 mfmp4srcsnk!MFCreateQTMovie+0x00000030
	2daf9600 mfmp4srcsnk!CMFMP4PropertyHandler::LoadMetadataProvider+0x0000013e
	2daf3d9a mfmp4srcsnk!CMFMP4PropertyHandler::InternalInitialize+0x000000ba
	2daf8782 mfmp4srcsnk!CMFPropHandlerBase::Initialize+0x00000072
	74ced4a4 windows_storage!InitializeFileHandlerWithStream+0x00000184
	74cea966 windows_storage!CFileSysItemString::HandlerCreateInstance+0x000001ba
	74dcdab8 windows_storage!CFileSysItemString::_PropertyHandlerCreateInstance+0x00000069
	74ceb687 windows_storage!CFileSysItemString::LoadHandler+0x00000181
	74d88836 windows_storage!CFSFolder::LoadHandler+0x000000a6
	74d88090 windows_storage!CFSPropertyStoreFactory::_GetFileStore+0x00000148
	74d89189 windows_storage!CFSPropertyStoreFactory::_s_GetFileStore+0x00000019
	74d5662e windows_storage!CFSPropertyStoreFactory::_GetMultiplexPropertyStore+0x00000217	

As we can see, a pointer in eax register is being dereferenced causing a critical exception because memory at the pointed address is freed. Going back and stepping out of the CMP4MetadataHandler::AddQTMetadata method we can see that dereferenced pointer is taken from an array which contains two elements (2 pairs of pointers):

79d25e1f 33f6           xor     esi, esi
79d25e21 8d83b0000000   lea     eax, [ebx+0B0h]
79d25e27 39b3b4000000   cmp     dword ptr [ebx+0B4h], esi
79d25e2d 7633           jbe     mfmp4srcsnk!CQTMovie::CreateQTMovie+0x182 (79d25e62)
79d25e2f 8b00           mov     eax, dword ptr [eax]
79d25e31 8b8bac000000   mov     ecx, dword ptr [ebx+0ACh]
79d25e37 ff34f0         push    dword ptr [eax+esi*8]
79d25e3a ff74f004       push    dword ptr [eax+esi*8+4]
79d25e3e e87c020000     call    mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata (79d260bf)
79d25e43 8bf8           mov     edi, eax
79d25e45 85ff           test    edi, edi
79d25e47 0f88d7fb0300   js      mfmp4srcsnk!CQTMovie::CreateQTMovie+0x3fd44 (79d65a24)
79d25e4d 46             inc     esi
79d25e4e 8d83b0000000   lea     eax, [ebx+0B0h]
79d25e54 3bb3b4000000   cmp     esi, dword ptr [ebx+0B4h]
79d25e5a 72d3           jb      mfmp4srcsnk!CQTMovie::CreateQTMovie+0x14f (79d25e2f)

0:005> dd [ebx+0B4h] L1
22926fbc  00000002

0:005> dd poi(eax)
2292afd8  22928fb8 22928f60 22970f18 22970ec8
2292afe8  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
2292aff8  c0c0c0c0 c0c0c0c0 ???????? ????????

0:005> ln poi(22928fb8)

(79ce174c)   mfmp4srcsnk!CQTMovieHeader::`vftable'   |  (79ce1778)   mfmp4srcsnk!CQTChunkLargeOffsetAtom::`vftable'
Exact matches:
0:005> ln poi(22970f18)

(79ce7444)   mfmp4srcsnk!CQTMetadataMapAtom::`vftable'   |  (79ce7470)   mfmp4srcsnk!CQTMetadataMapDataIndexAtom::`vftable'
Exact matches:	

Both pointers related with CQTMetadataMapAtom (22970f18, 22970ec8) have been released already during CMP4MetadataAtom::vector deleting destructor object destruction. To answer on question where CQTMetadataMapAtom` object has been added to that array and why later it got released we need to go back a bit and take a deeper look at the QuickTime file format.

The QuickTime file format is organized in a form of atoms, the atoms we will focus on are related to Metadata and described here: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW8 Deeper analysis pointed out that CQTMetadataMapAtom object is related with ilst structure in the metadata atom tree. In our PoC that structure is located at offset 0x807. Metadata atom tree and related with them objects look in the following way :

CQTMovie::CreateQTMovie			
	'meta' - CMP4MetadataAtom::Create
		'hdlr' - CQTHandlerAtom::Create
		'keys' - CQTMetadataKeysAtom::Create
		'ilst' - CQTMetadataMapAtom::CQTMetadataMapAtom
			'data' -  CQTMetadataMapDataIndexAtom

Further analysis showed that the CQTMetadataMapAtom object is added to the array mentioned above when the ilst structure is parsed successfully. The code responsible of these action is located inside CMP4MetadataAtom::CreateChildAtom:

Line 1 	int __stdcall CMP4MetadataAtom::CreateChildAtom(struct_this *this, unsigned int a2, unsigned int a3, unsigned int a4, struct CQTAtom **a5)
Line 2 	{
Line 3 	(...)
Line 4 		case 'ilst':
Line 5 		  v29 = (CQTMetadataMapAtom *)operator new(0x138u);
Line 6 		  if ( v29 )
Line 7 			objMetadataMapAtom = CQTMetadataMapAtom::CQTMetadataMapAtom(v29);
Line 8 		  else
Line 9 			objMetadataMapAtom = 0;
Line 10		  erroCode = CQTAtom::CreateTypedAtom((struct CQTAtom *)&retObjectMapAtom, (unsigned int)objMetadataMapAtom, &v54, v51, v52);
Line 11		  if ( erroCode < 0 )
Line 12		  {
Line 13			return erroCode;
Line 14		  }
Line 15		  v33 = (*(int (__thiscall **)(_DWORD, struct_this *, CQTMovie **))(this->cqtatom0 + 64))(// CQTAtom::GetOwningMovie (79d31160)
Line 16				  *(_DWORD *)(this->cqtatom0 + 64),
Line 17				  this,
Line 18				  &thisQTMovie);      
Line 19		  if ( v33 >= 0 )
Line 20		  {
Line 21			if ( retObjectMapAtom )
Line 22			  v6 = (struct CQTAtom *)((char *)retObjectMapAtom + 80);
Line 23			v35 = CQTMovie::TrackMetadataInTheProvider(thisQTMovie, retObjectMapAtom, v6);
Line 24		(...)

Looking inside CQTMovie::TrackMetadataInTheProvider, we can see an add operation :

Line 1	int __thisCQTMoviecall CQTMovie::TrackMetadataInTheProvider(CQTMovie *thisCQTMovie, struct CQTAtom *a2, struct IQTMetadata *a3)
Line 2	{
Line 3	  (...)
Line 4	  if ( *((_DWORD *)thisCQTMovie + 43) )
Line 5	  {
Line 6
Line 7		v13 = CMP4MetadataHandler::AddQTMetadata(*((CMP4MetadataHandler **)v3 + 43), a2, a3);

Next the atom inside our file being still a part of metadata (which is important in our context) is located at offset 0x8CD and that is a free atom.

08CDh: 99 00 04 00 66 72 65 65                          ô...free

The first 4 bytes represent its size which is equal 0x99000400 bytes. Its size is malformed which during the metadata parsing via CMP4MetadataAtom::ParseAtom cause an error. The error on that atoms tree level causes the CMP4MetadataAtom object representing meta atom and its children to be released. Of course one of its children is the CQTMetadataMapAtom object previously added to the array. Below is when CMP4MetadataAtom object is being released with all its children:

eax=79ce103c ebx=c00d36be ecx=79d2d080 edx=02d10000 esi=79d2d080 edi=79d3c2a0
eip=79d79d5b esp=0ab5f7c0 ebp=0ab5f7dc iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
mfmp4srcsnk!CQTAtom::CreateTypedAtom+0x453eb:
79d79d5b ffd6            call    esi {mfmp4srcsnk!CQTAtom::Release (79d2d080)}
0:005> kb
 # ChildEBP RetAddr  Args to Child              
00 0ab5f7dc 79d3693e 0b4acfac 0b4eef78 0ab5f81c mfmp4srcsnk!CQTAtom::CreateTypedAtom+0x453eb
01 0ab5f8d8 79d34559 0b4acf08 6d657461 000005b9 mfmp4srcsnk!CQTMovie::CreateChildAtom+0x34e
02 0ab5f928 79d342a8 0b4a6330 00000008 00000cc5 mfmp4srcsnk!CQTAtom::ScanChildrenInBuffer+0x249
03 0ab5f954 79d25d78 0b4acf08 00000000 78af74b0 mfmp4srcsnk!CQTAtom::ScanChildren+0xc8
04 0ab5f988 79d24124 0b4aafe8 00000000 0ae62ef8 mfmp4srcsnk!CQTMovie::CreateQTMovie+0x98
05 0ab5fa88 79d239a6 0af5af98 00000000 0ae62ef8 mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x1c6
06 0ab5fab0 79d22ff3 00000000 0ae62ef8 0af3add0 mfmp4srcsnk!MFCreateQTMovie+0x30
07 0ab5fb00 79d245d7 0ab5fce8 0ab5fd04 0ab5fd04 mfmp4srcsnk!CMPEG4MediaSourcePlugin::FinishParsingHeader+0xd2
08 0ab5fb6c 79d25255 0af5af98 00000000 00000000 mfmp4srcsnk!CMPEG4MediaSourcePlugin::BeginParsingHeader+0x335
09 0ab5fbcc 79d24a72 00000cf5 00000000 0af5af98 mfmp4srcsnk!CMPEG4MediaSourcePlugin::ParseHeaderInternal+0x232
0a 0ab5fcb4 79d1faf0 0af3add4 00000cf5 00000000 mfmp4srcsnk!CMPEG4MediaSourcePlugin::ParseHeader+0x332
0b 0ab5fd14 79d1f966 0af56fa8 0ab5fd50 6a68417e mfmp4srcsnk!CMFByteStreamMediaSource::OnByteStreamReadHeader+0x184
0c 0ab5fd20 6a68417e 0af46e34 0af56fa8 05895fc0 mfmp4srcsnk!CMFByteStreamMediaSource::OnByteStreamReadHeaderAsyncCallback::Invoke+0x16
0d 0ab5fd50 6a6886ef 0588bf98 6a6884f0 0a8e6f70 RTWorkQ!CSerialWorkQueue::QueueItem::ExecuteWorkItem+0x9e
0e 0ab5fd8c 77437dc4 0ab5fe9c 05895fc0 0a8e6f70 RTWorkQ!ThreadPoolWorkCallback+0x1ff
0f 0ab5fdc0 77436acc 0ab5fe9c 0a8e6fe8 6a751895 ntdll!TppWorkpExecuteCallback+0x144
10 0ab5ff70 75966359 0a6c6ee0 75966340 0ab5ffdc ntdll!TppWorkerThread+0x72c
11 0ab5ff80 77447a94 0a6c6ee0 6a751839 00000000 KERNEL32!BaseThreadInitThunk+0x19
12 0ab5ffdc 77447a64 ffffffff 77468e4e 00000000 ntdll!__RtlUserThreadStart+0x2f
13 0ab5ffec 00000000 774363a0 0a6c6ee0 00000000 ntdll!_RtlUserThreadStart+0x1b

0:005> dd esp L1
0ab5f7c0  0b4eef84 

0:005> ln poi(0b4eef84)

(79ce103c)   mfmp4srcsnk!CMP4MetadataAtom::`vftable'   |  (79ce1064)   mfmp4srcsnk!CQTEditList::`vftable'
Exact matches:	

Further after all atoms from the file are parsed we land in the situation presented at the beginning where library is trying to dereference the freed CQTMetadataMapAtom object. Keeping in mind the fact that between releasing an CQTMetadataMapAtom object and triggering the UAF vulnerability an attacker has multiple options to spray the heap using different types of atoms, as such this use-after-free vulnerability can result in code execution.

Crash Information

(48b0.7278): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0b4f6ec8 ebx=0b4f6f18 ecx=0b532ee8 edx=79cefb0c esi=00000001 edi=00000000
eip=79d260d9 esp=0ab5f938 ebp=0ab5f950 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata+0x1a:
79d260d9 8b30            mov     esi,dword ptr [eax]  ds:002b:0b4f6ec8=????????
0:005> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

*** WARNING: Unable to verify checksum for SimplePlay.exe

KEY_VALUES_STRING: 1

	Key  : AV.Fault
	Value: Read

	Key  : Analysis.CPU.Sec
	Value: 1

	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: 99

	Key  : Analysis.System
	Value: CreateObject

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

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


NTGLOBALFLAG:  2000000

APPLICATION_VERIFIER_FLAGS:  0

APPLICATION_VERIFIER_LOADED: 1

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 79d260d9 (mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata+0x0000001a)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 0b4f6ec8
Attempt to read from address 0b4f6ec8

FAULTING_THREAD:  00007278

PROCESS_NAME:  SimplePlay.exe

READ_ADDRESS:  0b4f6ec8 

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:  0b4f6ec8

STACK_TEXT:  
0ab5f950 79d25e43 0b4f6ec8 0b4f6f18 00000000 mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata+0x1a
0ab5f988 79d24124 0b4aafe8 00000000 0ae62ef8 mfmp4srcsnk!CQTMovie::CreateQTMovie+0x163
0ab5fa88 79d239a6 0af5af98 00000000 0ae62ef8 mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x1c6
0ab5fab0 79d22ff3 00000000 0ae62ef8 0af3add0 mfmp4srcsnk!MFCreateQTMovie+0x30
0ab5fb00 79d245d7 0ab5fce8 0ab5fd04 0ab5fd04 mfmp4srcsnk!CMPEG4MediaSourcePlugin::FinishParsingHeader+0xd2
0ab5fb6c 79d25255 0af5af98 00000000 00000000 mfmp4srcsnk!CMPEG4MediaSourcePlugin::BeginParsingHeader+0x335
0ab5fbcc 79d24a72 00000cf5 00000000 0af5af98 mfmp4srcsnk!CMPEG4MediaSourcePlugin::ParseHeaderInternal+0x232
0ab5fcb4 79d1faf0 0af3add4 00000cf5 00000000 mfmp4srcsnk!CMPEG4MediaSourcePlugin::ParseHeader+0x332
0ab5fd14 79d1f966 0af56fa8 0ab5fd50 6a68417e mfmp4srcsnk!CMFByteStreamMediaSource::OnByteStreamReadHeader+0x184
0ab5fd20 6a68417e 0af46e34 0af56fa8 05895fc0 mfmp4srcsnk!CMFByteStreamMediaSource::OnByteStreamReadHeaderAsyncCallback::Invoke+0x16
0ab5fd50 6a6886ef 0588bf98 6a6884f0 0a8e6f70 RTWorkQ!CSerialWorkQueue::QueueItem::ExecuteWorkItem+0x9e
0ab5fd8c 77437dc4 0ab5fe9c 05895fc0 0a8e6f70 RTWorkQ!ThreadPoolWorkCallback+0x1ff
0ab5fdc0 77436acc 0ab5fe9c 0a8e6fe8 6a751895 ntdll!TppWorkpExecuteCallback+0x144
0ab5ff70 75966359 0a6c6ee0 75966340 0ab5ffdc ntdll!TppWorkerThread+0x72c
0ab5ff80 77447a94 0a6c6ee0 6a751839 00000000 KERNEL32!BaseThreadInitThunk+0x19
0ab5ffdc 77447a64 ffffffff 77468e4e 00000000 ntdll!__RtlUserThreadStart+0x2f
0ab5ffec 00000000 774363a0 0a6c6ee0 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~5s ; .cxr ; kb

SYMBOL_NAME:  mfmp4srcsnk!CMP4MetadataHandler::AddQTMetadata+1a

MODULE_NAME: mfmp4srcsnk

IMAGE_NAME:  mfmp4srcsnk.dll

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_AVRF_c0000005_mfmp4srcsnk.dll!CMP4MetadataHandler::AddQTMetadata

OS_VERSION:  10.0.18362.239

BUILDLAB_STR:  19h1_release_svc_prod1

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 10

FAILURE_ID_HASH:  {9956042b-a2be-cc37-6d5b-94e2c5f99e95}

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

0:005> lmv a eip
Browse full module list
start    end        module name
79ce0000 79ea7000   mfmp4srcsnk   (pdb symbols)          C:\ProgramData\Dbg\sym\mfmp4srcsnk.pdb\FC5D6B5679940FBFF32098D3EE48055E1\mfmp4srcsnk.pdb
	Loaded symbol image file: C:\WINDOWS\SysWOW64\mfmp4srcsnk.dll
	Image path: C:\WINDOWS\SysWOW64\mfmp4srcsnk.dll
	Image name: mfmp4srcsnk.dll
	Browse all global symbols  functions  data
	Image was built with /Brepro flag.
	Timestamp:        D183C844 (This is a reproducible build file hash, not a timestamp)
	CheckSum:         001D37ED
	ImageSize:        001C7000
	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 MPEG4 Source and Sink DLL
		OriginalFilename: mfmp4srcsnk.dll
		ProductVersion:   10.0.18362.207
		FileVersion:      10.0.18362.207 (WinBuild.160101.0800)
		FileDescription:  Media Foundation MPEG4 Source and Sink DLL
		LegalCopyright:   © Microsoft Corporation. All rights reserved.

Timeline

2019-09-23 - Vendor Disclosure
2019-11-12 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.