CVE-2019-1430
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.
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
https://docs.microsoft.com/pl-pl/windows/win32/medfound/microsoft-media-foundation-sdk
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-416: Use After Free
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.
(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.
2019-09-23 - Vendor Disclosure
2019-11-12 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.