CVE-2020-0738
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.
Windows 10 - Media Foundation ASF Source and Sink DLL - 10.0.18362.207 (WinBuild.160101.0800) x86
https://docs.microsoft.com/en-us/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-704: Incorrect Type Conversion or Cast
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.
(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.
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
Discovered by Marcin 'Icewall' Noga of Cisco Talos.