CVE Number

CVE-2020-0687

Researcher: linhlhq from Infiniti Team – VinCSS (a member of Vingroup).

Summary

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a test exploit to invoke a sequence of library APIs. This report describes an issue triggered by a malformed font file in fontsub.dll code through our exploit.

Our initial tested version

Windows 10 x64 version 1909 with fontsub.dll version 10.0.18362.535 (WinBuild.160101.0800).

Affected version (confirmed by Microsoft)

All version of Windows from Windows 7 to Windows 10 latest version (prior to Patch Tuesday this month) and Windows Server 2008 to Windows Server latest version (prior to Patch Tuesday this month). See CVE-2020-0687 link above for more details.

CVSSv3

Score 8.8
CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C

Details

During fuzzing 2 APIs of fontsub.dll, an invalid font file will cause an error in the MergeFontPackage function.

Function MergeFontPackage is shown below:

unsigned long MergeFontPackage(

  const unsigned char  *puchMergeFontBuffer,

  const unsigned long  ulMergeFontBufferSize,

  const unsigned char  *puchFontPackageBuffer,

  const unsigned long  ulFontPackageBufferSize,

  unsigned char        **ppuchDestBuffer,

  unsigned long        *pulDestBufferSize,

  unsigned long        *pulBytesWritten,

  const unsigned short usMode,

  CFP_ALLOCPROC        lpfnAllocate,

  CFP_REALLOCPROC      lpfnReAllocate,

  CFP_FREEPROC         lpfnFree,

  void                 *lpvReserved

);


The process flow of the function is shown below:

Figure 1: Processing flow of the MergeFontPackage function

After debugging the data stream, we can see that the code of the ReadTableIntoStructure test has the following problem: MergeEblcEbdtTables function after calculating the capacity of struct bitmaptable. It will initialize the arr variable with size_arr:

Figure 2: bitmaptable initialization handler function in MergeEblcEbdtTables

Then run into the while loop to execute the ReadTableIntoStructure function, the condition to exit the loop is when the variable runs j > unk_v3 (value of Table_array).


Inside the ReadTableIntoStructure function, the processing part is shown below:

Figure 3: The processing code that causes an error in the ReadTableIntoStructure function

It also runs a loop to fill in the struct bitmaptable. In this function, we also check to see if the capacity of arr is exceeded, but there is a problem in line 156 where it checks size_1 with the capacity of arr is size_arr, but the placement is not reasonable.


Take the following example:

  • If size_1 = 1 and bitmaptable-> size_arr = 2 => the condition in line 156 will not be satisfied, so the while loop will continue.
  • Go to test i with glyphArray. Assuming i will be less than glyphArray => the condition in line 166 is not satisfied and the program returns to the while loop at this time size_1 is equal to 2 and an error occurs in line 150.

Figure 4: Crash context

This leads to out of bound write memory. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration.

 

Crash information

(6b80.7284): Access violation – code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

FONTSUB!ReadTableIntoStructure+0x22f:

00007ffa`1f0e485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax ds:000001b4`6ad3f010=????

0:000> !analyze -v

*******************************************************************************

*                                                                             *

*                        Exception Analysis                                   *

*                                                                             *

*******************************************************************************

KEY_VALUES_STRING: 1

TIMELINE_ANALYSIS: 1

Timeline: !analyze.Start

Name: <blank>

Time: 2020-04-02T12:27:38.906Z

Diff: 1093 mSec

Timeline: Dump.Current

Name: <blank>

Time: 2020-04-02T12:27:40.0Z

Diff: 0 mSec

Timeline: Process.Start

Name: <blank>

Time: 2020-04-02T12:12:45.0Z

Diff: 895000 mSec

Timeline: OS.Boot

Name: <blank>

Time: 2020-03-23T12:28:16.0Z

Diff: 863964000 mSec

DUMP_CLASS: 2

DUMP_QUALIFIER: 0

FAULTING_IP:

FONTSUB!ReadTableIntoStructure+22f

00007ffa`1eba485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax

EXCEPTION_RECORD:  (.exr -1)

ExceptionAddress: 00007ffa1eba485b (FONTSUB!ReadTableIntoStructure+0x000000000000022f)

ExceptionCode: c0000005 (Access violation)

ExceptionFlags: 00000000

NumberParameters: 2

Parameter[0]: 0000000000000001

Parameter[1]: 000001e16eabf010

Attempt to write to address 000001e16eabf010

FAULTING_THREAD:  0000cde8

PROCESS_NAME:  fuzz_ttf.exe

FOLLOWUP_IP:

FONTSUB!ReadTableIntoStructure+22f

00007ffa`1eba485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax

WRITE_ADDRESS:  000001e16eabf010

ERROR_CODE: (NTSTATUS) 0xc0000005 – The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_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:  0000000000000001

EXCEPTION_PARAMETER2:  000001e16eabf010

WATSON_BKT_PROCSTAMP:  5e05a3f2

WATSON_BKT_MODULE:  FONTSUB.dll

WATSON_BKT_MODSTAMP:  22c86eba

WATSON_BKT_MODOFFSET:  1485b

WATSON_BKT_MODVER:  10.0.18362.535

MODULE_VER_PRODUCT:  Microsoft® Windows® Operating System

BUILD_VERSION_STRING:  18362.1.amd64fre.19h1_release.190318-1202

MODLIST_WITH_TSCHKSUM_HASH:  e0701885b4164630ff6784e9b6d075fc447148d6

MODLIST_SHA1_HASH:  e9d8cb4ef4ad38bb2bd153b069d6b052a809b0c9

NTGLOBALFLAG:  2000000

PROCESS_BAM_CURRENT_THROTTLED: 0

PROCESS_BAM_PREVIOUS_THROTTLED: 0

APPLICATION_VERIFIER_FLAGS:  0

PRODUCT_TYPE:  1

SUITE_MASK:  272

DUMP_TYPE:  fe

APPLICATION_VERIFIER_LOADED: 1

ANALYSIS_SESSION_HOST:  DESKTOP-CBBVQA8

ANALYSIS_SESSION_TIME:  04-02-2020 19:27:38.0906

ANALYSIS_VERSION: 10.0.17134.1 amd64fre

THREAD_ATTRIBUTES:

OS_LOCALE:  ENU

PROBLEM_CLASSES:

ID:     [0n309]

Type:   [@ACCESS_VIOLATION]

Class:  Addendum

Scope:  BUCKET_ID

Name:   Omit

Data:   Omit

PID:    [Unspecified]

TID:    [0xcde8]

Frame:  [0] : FONTSUB!ReadTableIntoStructure

ID:     [0n282]

Type:   [INVALID_POINTER_WRITE]

Class:  Primary

Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)

BUCKET_ID

Name:   Add

Data:   Omit

PID:    [Unspecified]

TID:    [0xcde8]

Frame:  [0] : FONTSUB!ReadTableIntoStructure

ID:     [0n96]

Type:   [AVRF]

Class:  Addendum

Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)

BUCKET_ID

Name:   Add

Data:   Omit

PID:    [0x3228]

TID:    [0xcde8]

Frame:  [0] : FONTSUB!ReadTableIntoStructure

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF

DEFAULT_BUCKET_ID:  INVALID_POINTER_WRITE_AVRF

PRIMARY_PROBLEM_CLASS:  APPLICATION_FAULT

LAST_CONTROL_TRANSFER:  from 00007ffa1eba5e8d to 00007ffa1eba485b

STACK_TEXT:

0000002a`b50fd620 00007ffa`1eba5e8d : 00000000`00000003 0000001c`00280027 00000038`004e004e 00000000`00000000 : FONTSUB!ReadTableIntoStructure+0x22f

0000002a`b50fd6d0 00007ffa`1eb9b6ed : 000001e1`6ea70f10 0000002a`b50fd9f0 00000000`00000000 00000000`0000000f : FONTSUB!MergeEblcEbdtTables+0xb79

0000002a`b50fd8f0 00007ffa`1eb9c13c : 00000000`00000000 0000002a`b50fdb81 00000000`ffffffff 00000000`0000ffff : FONTSUB!MergeFonts+0x699

0000002a`b50fdaa0 00007ffa`1eb91583 : 00000000`00000c7c 0000002a`b50fdcc8 0000002a`b50fdc18 0000002a`b50fdc20 : FONTSUB!MergeDeltaTTF+0x3dc

0000002a`b50fdbd0 00007ff6`feef1e4e : 000001e1`6cbc89a0 00000000`00003640 00000000`00000000 00000000`00000000 : FONTSUB!MergeFontPackage+0x133

0000002a`b50fdc60 00007ff6`feef21ba : 00000000`00000000 00000000`00000000 00000000`00000000 000001e1`6ca71fcb : fuzz_ttf+0x1e4e

0000002a`b50ffae0 00007ff6`feef332d : 00007ffa`31a0b590 00000000`00000000 00000000`00000000 00000000`00000000 : fuzz_ttf+0x21ba

0000002a`b50ffb40 00007ffa`31be7bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : fuzz_ttf+0x332d

0000002a`b50ffb80 00007ffa`33b2ced1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14

0000002a`b50ffbb0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

STACK_COMMAND:  ~0s ; .cxr ; kb

THREAD_SHA1_HASH_MOD_FUNC:  9ce9cd8861479d96159761a9691ba4c8c894d465

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  9d3f8671fbf17c2d1c0c9a4058647f93ece75fc6

THREAD_SHA1_HASH_MOD:  c36dc10ccf4919ee237948f385c765a7701b1bdd

FAULT_INSTR_CODE:  a448966

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  FONTSUB!ReadTableIntoStructure+22f

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: FONTSUB

IMAGE_NAME:  FONTSUB.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  22c86eba

FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_AVRF_c0000005_FONTSUB.dll!ReadTableIntoStructure

BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF_FONTSUB!ReadTableIntoStructure+22f

FAILURE_EXCEPTION_CODE:  c0000005

FAILURE_IMAGE_NAME:  FONTSUB.dll

BUCKET_ID_IMAGE_STR:  FONTSUB.dll

FAILURE_MODULE_NAME:  FONTSUB

BUCKET_ID_MODULE_STR:  FONTSUB

FAILURE_FUNCTION_NAME:  ReadTableIntoStructure

BUCKET_ID_FUNCTION_STR:  ReadTableIntoStructure

BUCKET_ID_OFFSET:  22f

BUCKET_ID_MODTIMEDATESTAMP:  22c86eba

BUCKET_ID_MODCHECKSUM:  24c8a

BUCKET_ID_MODVER_STR:  10.0.18362.535

BUCKET_ID_PREFIX_STR:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF_

FAILURE_PROBLEM_CLASS:  APPLICATION_FAULT

FAILURE_SYMBOL_NAME:  FONTSUB.dll!ReadTableIntoStructure

TARGET_TIME:  2020-04-02T12:27:53.000Z

OSBUILD:  18363

OSSERVICEPACK:  329

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

OSEDITION:  Windows 10 WinNt SingleUserTS

USER_LCID:  0

OSBUILD_TIMESTAMP:  unknown_date

BUILDDATESTAMP_STR:  190318-1202

BUILDLAB_STR:  19h1_release

BUILDOSVER_STR:  10.0.18362.1.amd64fre.19h1_release.190318-1202

ANALYSIS_SESSION_ELAPSED_TIME:  3a49

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:invalid_pointer_write_avrf_c0000005_fontsub.dll!readtableintostructure

FAILURE_ID_HASH:  {edfa825c-ba3b-c2d6-424f-ccecd5a7ca4c}

Followup:     MachineOwner

0:000> lmv a rip

Browse full module list

start             end                 module name

00007ffa`1f0d0000 00007ffa`1f0f2000   FONTSUB    (pdb symbols)          C:ProgramDatadbgsymfontsub.pdb2A2820FCD9D9D44522A8601FBA7839B71fontsub.pdb

Loaded symbol image file: C:WINDOWSSYSTEM32FONTSUB.dll

Image path: C:WINDOWSSYSTEM32FONTSUB.dll

Image name: FONTSUB.dll

Browse all global symbols  functions  data

Image was built with /Brepro flag.

Timestamp:        22C86EBA (This is a reproducible build file hash, not a timestamp)

CheckSum:         00024C8A

ImageSize:        00022000

File version:     10.0.18362.535

Product version:  10.0.18362.535

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:     fontsub

OriginalFilename: fontsub

ProductVersion:   10.0.18362.535

FileVersion:      10.0.18362.535 (WinBuild.160101.0800)

FileDescription:  Font Subsetting DLL

        LegalCopyright:   © Microsoft Corporation. All rights reserved.


An attacker who successfully exploited this vulnerability could take control of the affected system. An attacker could then install programs; view, change, or delete data; or create new accounts with full user rights. Users whose accounts are configured to have fewer user rights on the system could be less impacted than users who operate with administrative user rights.

There are multiple ways an attacker could exploit this vulnerability:

  • In a web-based attack scenario, an attacker could host a specially crafted website that is designed to exploit this vulnerability and then convince or lure users to browse the website. Normally, an attacker would have no way to force users to browse the attacker-controlled content. Instead, an attacker would have to convince users to take action, typically by getting them to click a link in an email or instant message that takes users to the attacker’s website, or by opening an attachment sent through email.
  • In a file-sharing attack scenario, an attacker could provide a specially crafted document file designed to exploit the vulnerability and then convince users to open the document file.

Figure 5: Attack vectors can happen in real life

 

Timeline 

2020-Jan-03 – Reported vendor

2020-Jan-09 – The vendor confirmed it was a bug

2020-Jan-13 – Updated detailed analysis for vendor

2020-Apr-14 – Public Release