NULL pointer dereference in Windows GDI bParseWin32MetaFile
TL;DR
A denial of service vulnerability exists when Windows GDI improperly handles objects in memory. Converting a specially crafted EMF
file to a WMF
may trigger a read access violation due to a NULL
pointer dereference and could allow denial of service.
Description
It seems that calling Metafile::EmfToWmfBits()
method on a specially crafted EMF
file may lead to memory corruption triggered by bGetNextRecord()
called by the bParseWin32Metafile()
function. The below is the relevant excerpt of the crash analysis from WinDbg
:
1FAULTING_IP:
2gdiplus!bGetNextRecord+34e6f
3747ae398 8b4104 mov eax,dword ptr [ecx+4]
4
5EXCEPTION_RECORD: (.exr -1)
6ExceptionAddress: 747ae398 (gdiplus!bGetNextRecord+0x00034e6f)
7 ExceptionCode: c0000005 (Access violation)
8 ExceptionFlags: 00000000
9NumberParameters: 2
10 Parameter[0]: 00000000
11 Parameter[1]: 00000004
12Attempt to read from address 00000004
The Metafile::EmfToWmfBits()
method converts an enhanced-format metafile to a Windows Metafile Format (WMF) metafile and stores the converted records in a specified buffer.
1Metafile::EmfToWmfBits(hEmf, 0, NULL, MM_TEXT, EmfToWmfBitsFlagsDefault);
Calling this method on the provided EMF
file in MM_TEXT
mapping mode and the EmfToWmfBitsFlagsDefault
options for the conversion will trigger a reproducable read access violation due to a NULL
pointer dereference.
PoC
The below PoC code can demonstrate the problem:
1HENHMETAFILE hEmf = GetEnhMetaFileW(L"PoC.emf");
2Metafile::EmfToWmfBits(hEmf, 0, NULL, MM_TEXT, EmfToWmfBitsFlagsDefault);
3
4DeleteEnhMetaFile(hEmf);
Upon compiling it and starting with the attached file in the current working directory, the expected crash is generated in bGetNextRecord()
:
1(2214.30f8): Access violation - code c0000005 (first chance)
2First chance exceptions are reported before any exception handling.
3This exception may be expected and handled.
4eax=00000001 ebx=00000001 ecx=00000000 edx=00effa58 esi=07f53e10 edi=00000000
5eip=747ae398 esp=00effa3c ebp=00effa5c iopl=0 nv up ei pl zr na pe nc
6cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
7gdiplus!bGetNextRecord+0x34e6f:
8747ae398 8b4104 mov eax,dword ptr [ecx+4] ds:002b:00000004=????????
9
100:000> kb
11 # ChildEBP RetAddr Args to Child
1200 00effa5c 747792ba 07f51130 00001000 00000074 gdiplus!bGetNextRecord+0x34e6f
1301 00effa74 747791e9 00000000 00000000 00000001 gdiplus!GdipConvertEmfToWmf+0x91
1402 00effab0 74778ed3 00000000 00000001 00000000 gdiplus!GdipGetWinMetaFileBitsEx+0x160
1503 00effb60 74778e64 00000000 00000001 00000000 gdiplus!ConvertEmfToPlaceableWmf+0x5f
1604 00effb78 00371807 d7462c87 00000000 00000000 gdiplus!GdipEmfToWmfBits+0x24
1705 00effc60 003718d6 d7462c87 00000000 00000000 ParseWin32Metafile!Gdiplus::Metafile::EmfToWmfBits+0x37 [C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\GdiplusMetafile.h @ 380]
1806 00effd54 00371fe3 00000001 07f45fa0 07ecbf20 ParseWin32Metafile!main+0x46
An access violation exception happened at 0x4
while attempting to read memory at 0x4
using a NULL pointer. The bug has been reproduced on a fully patched Windows 10 64-bit with a 32-bit PoC program loading version 10.0.18362.959 (x86) of gdi32full.dll
, but the 64-bit build of gdi32full.dll
also seems to be affected.
Timeline
⬅️ 2020-07-23: Reported issue to MSRC.
➡️ 2020-07-23: MSRC opened case 60123.
➡️ 2020-08-03: MSRC indicated that this is a moderate issue and won’t be fixed.
➡️ 2020-08-25: Coordinated public release of advisory.