Talos Vulnerability Report

TALOS-2025-2157

High-Logic FontCreator GSUB subtable Out-Of-Bounds Read Vulnerability

June 2, 2025
CVE Number

CVE-2025-20001

SUMMARY

An out-of-bounds read vulnerability exists in High-Logic FontCreator 15.0.0.3015. A specially crafted font file can trigger this vulnerability which can lead to disclosure of sensitive information. An attacker needs to trick the user into opening the malicious file to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

High-Logic FontCreator 15.0.0.3015

PRODUCT URLS

FontCreator - https://www.high-logic.com/font-editor/fontcreator

CVSSv3 SCORE

6.5 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N

CWE

CWE-125 - Out-of-bounds Read

DETAILS

FontCreator is a font editor application. It allows users to create, edit, and convert fonts, making it a popular tool among designers, typographers, and developers who work with custom typefaces.

An OpenType font file starts with a table directory (TableDirectory ) followed by one or more table record (TableRecord) entries. The structure of TableDirectory is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x04  sfntVersion (0x00010000 or 0x4F54544F  )
0x04    0x02  numTables
0x06    0x02  searchRange
0x08    0x02  entrySelector
0x0c    0x02  rangeShift

If the value of the sfntVersion field is 0x00010000 or 0x74727565, the font contains TrueType data. The CFF data will be present if the value of sfntVersion is 0x4F54544F (OTTO). The numTables field specifies the number of TableRecord entries present in the font file. The structure of a TableRecord entry is as follows:

Offset Size   Name
------ ----- ----------------------------------
0x00    0x04  tableTag
0x04    0x04  tableChecksum
0x08    0x04  tableOffset
0x0C    0x04  tableLength

tableTag is the name of TableRecord. The tableOffset field specifies the offset of the table from the beginning of the file. The tableLength indicates the length of the table. The structure of each TableRecord depends on the type table, which is defined by the tableTag.

This vulnerability is related to the GSUB table. For the GSUB table, the value of the tableTag field is the string GSUB.

The GSUB table defines glyph substitution data. The structure of the GSUB table header is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02  GSUB_MajorVersion
0x02    0x02  GSUB_MinorVersion
0x04    0x02  scriptListOffset
0x06    0x02  featureListOffset
0x08    0x02  lookupListOffset

Here the lookupListOffset field is important for this vulnerability. It indicates the offset to LookupList table from the beginning of the GSUB table.

The LookupList table consists an array of offsets to Lookup tables. The structure of LookupList table is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02    lookupCount (N)
0x02    0x02*N  lookupOffsets[N]

The lookupCount field indicates the number of elements in the lookupOffsets array. The lookupOffsets array contains offsets pointing to individual Lookup tables from the beginning of the LookupList.

A Lookup table contains one or more substitution rules that help shape text appearance. The structure of the Lookup table is as follows:”

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02      lookupType 
0x02    0x02      lookupFlag
0x04    0x02      subTableCount (M)
0x06    0x02*M    subtableOffsets[M]

A Lookup table contains M subtable tables, as indicated by the subTableCount field. The subtableOffsets array contains offsets pointing to individual subtable tables from the beginning of the Lookup table.

This vulnerability occurs when the first 2 bytes of the subtable table are 0x02. The structure of such a subtable table is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02      subtableFormat 
0x02    0x02      coverageOffset
0x04    0x02      glyphCount (P)
0x06    0x02 * P  subsitutes[P] 

The value of the subtableFormat field must be 0x02 for this vulnerability. The coverageOffset contains the offset of the Coverage table from the beginning of the subtable table.

The first 2 bytes of the Coverage table indicate the type of the Coverage table. If the first two bytes are 0x01, the Coverage table type is CoverageFormat1. If the first two bytes are 0x02, the Coverage table type is CoverageFormat2. This vulnerability is related to the CoverageFormat2 table. The structure of the CoverageFormat2 table is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02        coverageFormat 
0x02    0x02        rangeCount (Q)
0x04    0x06 * Q    rangeRecords[Q]

The value of coverageFormat is 0x02 for the CoverageFormat2 table. The rangeRecords contains an array of RangeRecord, and the number of RangeRecord entries present in the rangeRecords array is indicated by the rangeCount field. The structure of a RangeRecord is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02      startGlyphID 
0x02    0x02      endGlyphID
0x04    0x02      startCoverageIndex

This vulnerability is related to the processing of a subtable and its Coverage table. We can observe the following in the debugger (with PageHeap enabled):

0:007> g
FontCreator!_dbk_fcall_wrapper+0xfad23c:
00000000`01a2b54c 4889f1          mov     rcx,rsi
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad23f:
00000000`01a2b54f e83c9c60ff      call    FontCreator!_dbk_fcall_wrapper+0x5b6e80 (00000000`01035190) ;<---------- (1)
0:007> dq rcx
000001ff`e8520590  00000000`00bee5e0 000001ff`c37d2050
000001ff`e85205a0  00000000`00001c6e 00000000`0000055c
000001ff`e85205b0  00000000`00002000 00000000`00000000
000001ff`e85205c0  000001ff`b7ee81b0 000001ff`e851d9a0
000001ff`e85205d0  00000000`0182d538 000001ff`c37dc9e0
000001ff`e85205e0  00000000`00000000 00000000`01c8e0b0
000001ff`e85205f0  000001ff`d7cd09e0 00000000`00000000
000001ff`e8520600  00000000`00000000 000001ff`e851d9a0

0:007> db 000001ff`c37d2050+55c   ;<---------------------------------------------------------- (2)
000001ff`c37d25ac  00 02 0d 0e 00 0a 02 a2-02 a3 02 a4 02 a6 02 a7  ................
000001ff`c37d25bc  02 a9 02 a1 02 a5 02 a8-02 aa 00 03 00 00 00 01  ................
000001ff`c37d25cc  0c f4 00 05 40 00 0c ca-0c ca 0c ca 0c 7c 00 01  ....@........|..
000001ff`c37d25dc  00 00 00 19 00 02 0c da-41 00 00 00 02 f1 02 f2  ........A.......
000001ff`c37d25ec  ff ff ff 4c 5a f7 02 ef-02 f3 02 f6 02 f8 89 02  ...LZ...........
000001ff`c37d25fc  0c c0 00 0a 02 2f 02 30-02 31 02 33 02 34 02 36  ...../.0.1.3.4.6
000001ff`c37d260c  02 2e 02 32 02 35 02 37-00 03 00 00 00 01 0c a6  ...2.5.7........
000001ff`c37d261c  00 06 0c 7c 0c 7c 0c 7c-0c 7c 0c 7c 0c 2e 00 01  ...|.|.|.|.|....
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad244:
00000000`01a2b554 6683e801        sub     ax,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad248:
00000000`01a2b558 6685c0          test    ax,ax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad24b:
00000000`01a2b55b 740b            je      FontCreator!_dbk_fcall_wrapper+0xfad258 (00000000`01a2b568) [br=0]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad24d:
00000000`01a2b55d 6683e801        sub     ax,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad251:
00000000`01a2b561 6685c0          test    ax,ax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad254:
00000000`01a2b564 751c            jne     FontCreator!_dbk_fcall_wrapper+0xfad272 (00000000`01a2b582) [br=0]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad256:
00000000`01a2b566 eb0d            jmp     FontCreator!_dbk_fcall_wrapper+0xfad265 (00000000`01a2b575)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad265:
00000000`01a2b575 4889d9          mov     rcx,rbx
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad268:
00000000`01a2b578 4889f2          mov     rdx,rsi
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfad26b:
00000000`01a2b57b e8200b0000      call    FontCreator!_dbk_fcall_wrapper+0xfadd90 (00000000`01a2c0a0) ;<---------------------------- (3)

At (1), a method is called to read the subtableFormat field of the subtable. The content of the subtable can be observed at (2). Here, the value of the subtableFormat field is 0x02, so the method is called at (3) to process the subtable table.

:007> p
FontCreator!_dbk_fcall_wrapper+0xfade47:
00000000`01a2c157 0fb74004        movzx   eax,word ptr [rax+4] ds:000001ff`c4bbea94=000a ; <------------------------- (4)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade4b:
00000000`01a2c15b 03c0            add     eax,eax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade4d:
00000000`01a2c15d 898588000000    mov     dword ptr [rbp+88h],eax ss:00000056`17b7ef58=010351bd
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade53:
00000000`01a2c163 488d8db0000000  lea     rcx,[rbp+0B0h]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade5a:
00000000`01a2c16a 8b958c000000    mov     edx,dword ptr [rbp+8Ch] ss:00000056`17b7ef5c=00000006
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade60:
00000000`01a2c170 039588000000    add     edx,dword ptr [rbp+88h] ss:00000056`17b7ef58=00000014
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade66:
00000000`01a2c176 8bd2            mov     edx,edx
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade68:
00000000`01a2c178 e803d603ff      call    FontCreator+0x9780 (00000000`00a69780) ; <------------------------- (5)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade6d:
00000000`01a2c17d 488b8de8000000  mov     rcx,qword ptr [rbp+0E8h] ss:00000056`17b7efb8=000001ffe8520590
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade74:
00000000`01a2c184 488b85b0000000  mov     rax,qword ptr [rbp+0B0h] ss:00000056`17b7ef80=000001ffe8764e50

0:007> db 000001ffe8764e50    ; <------------------------- (6)
000001ff`e8764e50  01 00 0e 0d 0a 00 00 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e60  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e70  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e80  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e90  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764ea0  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764eb0  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764ec0  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................

At (4), the glyphCount value is read and used to calculate the size of the subtable, excluding the coverage table. Its size is calculated using the formula (2 * glyphCount + 6). A custom allocator is called at (5) to allocate the vulnerable buffer. The content of the vulnerable buffer is examined at (6).

:007> p
FontCreator!_dbk_fcall_wrapper+0xfade7b:
00000000`01a2c18b 488d5006        lea     rdx,[rax+6]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade7f:
00000000`01a2c18f 448b8588000000  mov     r8d,dword ptr [rbp+88h] ss:00000056`17b7ef58=00000014
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade86:
00000000`01a2c196 488b85e8000000  mov     rax,qword ptr [rbp+0E8h] ss:00000056`17b7efb8=000001ffe8520590
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade8d:
00000000`01a2c19d 488b00          mov     rax,qword ptr [rax] ds:000001ff`e8520590=0000000000bee5e0
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade90:
00000000`01a2c1a0 ff5040          call    qword ptr [rax+40h] ds:00000000`00bee620=0000000000c2f730 ; <------------------------- (7)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfade93:
00000000`01a2c1a3 488b85b0000000  mov     rax,qword ptr [rbp+0B0h] ss:00000056`17b7ef80=000001ffe8764e50
0:007> dw 000001ffe8764e50  ; <----------------------------------------------- (8)
000001ff`e8764e50  0001 0d0e 000a a202 a302 a402 a602 a702
000001ff`e8764e60  a902 a102 a502 a802 aa02 00fd 00fd 00fd
000001ff`e8764e70  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764e80  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764e90  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764ea0  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764eb0  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764ec0  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
[...]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadecc:
00000000`01a2c1dc 488b8db8000000  mov     rcx,qword ptr [rbp+0B8h] ss:00000056`17b7ef88=000001ffe8761ef0
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfaded3:
00000000`01a2c1e3 488b95e8000000  mov     rdx,qword ptr [rbp+0E8h] ss:00000056`17b7efb8=000001ffe8520590
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadeda:
00000000`01a2c1ea e841830200      call    FontCreator!_dbk_fcall_wrapper+0xfd6220 (00000000`01a54530) ;<---------------------- (9)

At (7), a method is called to read the substitutes array and write it to the vulnerable buffer. The content of the vulnerable buffer is examined at (8) after reading the substitutes array. Next, a method is called at (9) to process the Coverage table.

0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6238:
00000000`01a54548 e8430c5eff      call    FontCreator!_dbk_fcall_wrapper+0x5b6e80 (00000000`01035190) ;<---------------------- (10)

0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd623d:
00000000`01a5454d 6683e801        sub     ax,1
0:007> r                                                             ;<---------------------- (11)
rax=0000000000000002 rbx=000001ffe8761ef0 rcx=0000000000000002
rdx=0000005617b7ee6e rsi=000001ffe8520590 rdi=0000000000000000
rip=0000000001a5454d rsp=0000005617b7ee90 rbp=0000005617b7eed0
 r8=0000000000000002  r9=000000000000126c r10=0000000001896d60
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
FontCreator!_dbk_fcall_wrapper+0xfd623d:
00000000`01a5454d 6683e801        sub     ax,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6241:
00000000`01a54551 6685c0          test    ax,ax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6244:
00000000`01a54554 740b            je      FontCreator!_dbk_fcall_wrapper+0xfd6251 (00000000`01a54561) [br=0]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6246:
00000000`01a54556 6683e801        sub     ax,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd624a:
00000000`01a5455a 6685c0          test    ax,ax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd624d:
00000000`01a5455d 751f            jne     FontCreator!_dbk_fcall_wrapper+0xfd626e (00000000`01a5457e) [br=0]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd624f:
00000000`01a5455f eb10            jmp     FontCreator!_dbk_fcall_wrapper+0xfd6261 (00000000`01a54571)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6261:
00000000`01a54571 4889d9          mov     rcx,rbx
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6264:
00000000`01a54574 4889f2          mov     rdx,rsi
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfd6267:
00000000`01a54577 e8e4010000      call    FontCreator!_dbk_fcall_wrapper+0xfd6450 (00000000`01a54760)  ;<---------------------- (12)

At (10), a method is called to read the first 2 bytes of the Coverage table. At (11), it is observed that this is a coverageFormat2 table, and a method is called at (12) to process the coverageFormat2 table. This method iterates through each RangeRecord field and calculates totalGlyphId using the following pseudo formula:

totalGlyphId = 0
for i in range (rangeCount):
    startGlyphID = struct.unpack(">H",rangeRecordsArr[6*i: 6*i+2])[0]
    endGlyphID = struct.unpack(">H",rangeRecordsArr[6*i+2: 6*i+4])[0]

    if startGlyphID <= endGlyphID:
        totalGlyphId += endGlyphID - startGlyphID + 1

Here, rangeRecordsArr contains rangeRecords array of the coverageFormat2 table.

:007> p
FontCreator!_dbk_fcall_wrapper+0xfadee8:
00000000`01a2c1f8 8b7110          mov     esi,dword ptr [rcx+10h] ds:000001ff`e8761f00=0003ae5a ;<---------------------- (13)
0:007> dq rcx
000001ff`e8761ef0  00000000`01a540d8 000001ff`e98c7370
000001ff`e8761f00  00000000`0003ae5a 00000000`0187bf88
000001ff`e8761f10  000001ff`e8761ef0 00000000`00000000
000001ff`e8761f20  00000000`00000000 00000000`028d1ed8
000001ff`e8761f30  00000000`00000000 00000000`00000000
000001ff`e8761f40  000001ff`d7b0b080 00000000`00000000
000001ff`e8761f50  00fd00fd`00fd00fd 00fd00fd`00fd00fd
000001ff`e8761f60  00fd00fd`00fd00fd 00fd00fd`00fd00fd
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadeeb:
00000000`01a2c1fb 83ee01          sub     esi,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadeee:
00000000`01a2c1fe 8985a4000000    mov     dword ptr [rbp+0A4h],eax ss:00000056`17b7ef74=00000000
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadef4:
00000000`01a2c204 39b5a4000000    cmp     dword ptr [rbp+0A4h],esi ss:00000056`17b7ef74=00000000
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadefa:
00000000`01a2c20a 0f8f86010000    jg      FontCreator!_dbk_fcall_wrapper+0xfae086 (00000000`01a2c396) [br=0]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf00:
00000000`01a2c210 2bf0            sub     esi,eax
0:007> r
rax=0000000000000000 rbx=0000000000000004 rcx=000001ffe8761ef0
rdx=000001ffaceea490 rsi=000000000003ae59 rdi=0000000000000000
rip=0000000001a2c210 rsp=0000005617b7eed0 rbp=0000005617b7eed0
 r8=000000000003d921  r9=0000005617b7ed98 r10=000001ffe98c7360
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei ng nz ac pe cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
FontCreator!_dbk_fcall_wrapper+0xfadf00:
00000000`01a2c210 2bf0            sub     esi,eax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf02:
00000000`01a2c212 83c601          add     esi,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf05:
00000000`01a2c215 48639da4000000  movsxd  rbx,dword ptr [rbp+0A4h] ss:00000056`17b7ef74=00000000 ;<---------------------- (14)
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf0c:
00000000`01a2c21c 488b85b8000000  mov     rax,qword ptr [rbp+0B8h] ss:00000056`17b7ef88=000001ffe8761ef0
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf13:
00000000`01a2c223 488b4010        mov     rax,qword ptr [rax+10h] ds:000001ff`e8761f00=000000000003ae5a
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf17:
00000000`01a2c227 483bd8          cmp     rbx,rax
0:007> r
rax=000000000003ae5a rbx=0000000000000000 rcx=000001ffe8761ef0
rdx=000001ffaceea490 rsi=000000000003ae5a rdi=0000000000000000
rip=0000000001a2c227 rsp=0000005617b7eed0 rbp=0000005617b7eed0
 r8=000000000003d921  r9=0000005617b7ed98 r10=000001ffe98c7360
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei pl nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
FontCreator!_dbk_fcall_wrapper+0xfadf17:
00000000`01a2c227 483bd8          cmp     rbx,rax
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf1a:
00000000`01a2c22a 7213            jb      FontCreator!_dbk_fcall_wrapper+0xfadf2f (00000000`01a2c23f) [br=1]
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf2f:
00000000`01a2c23f 488b85b8000000  mov     rax,qword ptr [rbp+0B8h] ss:00000056`17b7ef88=000001ffe8761ef0
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf36:
00000000`01a2c246 488b4008        mov     rax,qword ptr [rax+8] ds:000001ff`e8761ef8=000001ffe98c7370
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf3a:
00000000`01a2c24a 0fb70458        movzx   eax,word ptr [rax+rbx*2] ds:000001ff`e98c7370=0225
0:007> r
rax=000001ffe98c7370 rbx=0000000000000000 rcx=000001ffe8761ef0
rdx=000001ffaceea490 rsi=000000000003ae5a rdi=0000000000000000
rip=0000000001a2c24a rsp=0000005617b7eed0 rbp=0000005617b7eed0
 r8=000000000003d921  r9=0000005617b7ed98 r10=000001ffe98c7360
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei ng nz ac po cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297
FontCreator!_dbk_fcall_wrapper+0xfadf3a:
00000000`01a2c24a 0fb70458        movzx   eax,word ptr [rax+rbx*2] ds:000001ff`e98c7370=0225
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf3e:
00000000`01a2c24e 8985ac000000    mov     dword ptr [rbp+0ACh],eax ss:00000056`17b7ef7c=00000000
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf44:
00000000`01a2c254 488b85b0000000  mov     rax,qword ptr [rbp+0B0h] ss:00000056`17b7ef80=000001ffe8764e50
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf4b:
00000000`01a2c25b 48638da4000000  movsxd  rcx,dword ptr [rbp+0A4h] ss:00000056`17b7ef74=00000000
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfadf52:
00000000`01a2c262 0fb7444806      movzx   eax,word ptr [rax+rcx*2+6] ds:000001ff`e8764e56=02a2 ;<---------------------- (15)
0:007> db 000001ff`e8764e56
000001ff`e8764e56  a2 02 a3 02 a4 02 a6 02-a7 02 a9 02 a1 02 a5 02  ................
000001ff`e8764e66  a8 02 aa 02 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e76  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e86  fd 00 20 40 76 e8 ff 01-00 00 90 88 cd 00 00 00  .. @v...........
000001ff`e8764e96  00 00 50 76 ce 00 00 00-00 00 f0 93 e9 d7 ff 01  ..Pv............
000001ff`e8764ea6  00 00 70 46 28 b8 ff 01-00 00 20 94 e9 d7 ff 01  ..pF(..... .....
000001ff`e8764eb6  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
000001ff`e8764ec6  00 00 20 40 76 e8 ff 01-00 00 90 88 cd 00 b0 04  .. @v...........
0:007> dw 000001ff`e8764e56
000001ff`e8764e56  02a2 02a3 02a4 02a6 02a7 02a9 02a1 02a5
000001ff`e8764e66  02a8 02aa 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764e76  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764e86  00fd 4020 e876 01ff 0000 8890 00cd 0000
000001ff`e8764e96  0000 7650 00ce 0000 0000 93f0 d7e9 01ff
000001ff`e8764ea6  0000 4670 b828 01ff 0000 9420 d7e9 01ff
000001ff`e8764eb6  0000 0000 0000 0000 0000 0000 0000 0000
000001ff`e8764ec6  0000 4020 e876 01ff 0000 8890 00cd 04b0
0:007> u
FontCreator!_dbk_fcall_wrapper+0xfadf52:
00000000`01a2c262 0fb7444806      movzx   eax,word ptr [rax+rcx*2+6]
00000000`01a2c267 8985a8000000    mov     dword ptr [rbp+0A8h],eax
00000000`01a2c26d 488b85e0000000  mov     rax,qword ptr [rbp+0E0h]
00000000`01a2c274 488b4030        mov     rax,qword ptr [rax+30h]
00000000`01a2c278 488b4820        mov     rcx,qword ptr [rax+20h]
00000000`01a2c27c 8b95ac000000    mov     edx,dword ptr [rbp+0ACh]
00000000`01a2c282 e8597e2800      call    FontCreator!_dbk_fcall_wrapper+0x1235dd0 (00000000`01cb40e0)
00000000`01a2c287 84c0            test    al,al
0:007> bp 0000000001A2C384
0:007> g
Breakpoint 4 hit
FontCreator!_dbk_fcall_wrapper+0xfae074:
00000000`01a2c384 8385a400000001  add     dword ptr [rbp+0A4h],1 ss:00000056`17b7ef74=00000000
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfae07b:
00000000`01a2c38b 83ee01          sub     esi,1
0:007> r
rax=0000000000000000 rbx=0000000000000000 rcx=000001ffe6980120
rdx=000001ffe7b49a70 rsi=000000000003ae5a rdi=0000000000000000
rip=0000000001a2c38b rsp=0000005617b7eed0 rbp=0000005617b7eed0
 r8=0000000001010101  r9=0000005617b7ee58 r10=000001ffe98c7360
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
FontCreator!_dbk_fcall_wrapper+0xfae07b:
00000000`01a2c38b 83ee01          sub     esi,1
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfae07e:
00000000`01a2c38e 85f6            test    esi,esi
0:007> p
FontCreator!_dbk_fcall_wrapper+0xfae080:
00000000`01a2c390 0f857ffeffff    jne     FontCreator!_dbk_fcall_wrapper+0xfadf05 (00000000`01a2c215) [br=1] ;<---------------------- (16)

At (13), the value of totalGlyphId for the vulnerable subtable can be observed. Next, a loop starts at (14) and ends at (16), using totalGlyphId as the loop counter. It reads the substitutes array totalGlyphId times at (15). This vulnerability occurs when the value of 2 * glyphCount is less than totalGlyphId. The vulnerable condition is met here, so if we continue, a crash can be observed.

0:007> g
(1314.12e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FontCreator!_dbk_fcall_wrapper+0xfadf52:
00000000`01a2c262 0fb7444806      movzx   eax,word ptr [rax+rcx*2+6] ds:000001ff`e87d0000=????
0:007> r
rax=000001ffe8764e50 rbx=00000000000358d5 rcx=00000000000358d5
rdx=00000000000055fb rsi=0000000000005585 rdi=0000000000000000
rip=0000000001a2c262 rsp=0000005617b7eed0 rbp=0000005617b7eed0
 r8=0000000001010101  r9=0000005617b7ee58 r10=000001fff8156100
r11=000001ffc5a28fc8 r12=0000000000000000 r13=0000000000000000
r14=0000000001a47de0 r15=0000000000000000
iopl=0         nv up ei ng nz ac po cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010297
FontCreator!_dbk_fcall_wrapper+0xfadf52:
00000000`01a2c262 0fb7444806      movzx   eax,word ptr [rax+rcx*2+6] ds:000001ff`e87d0000=????
0:007> db rax
000001ff`e8764e50  01 00 0e 0d 0a 00 a2 02-a3 02 a4 02 a6 02 a7 02  ................
000001ff`e8764e60  a9 02 a1 02 a5 02 a8 02-aa 02 fd 00 fd 00 fd 00  ................
000001ff`e8764e70  fd 00 fd 00 fd 00 fd 00-fd 00 fd 00 fd 00 fd 00  ................
000001ff`e8764e80  fd 00 fd 00 fd 00 fd 00-20 40 76 e8 ff 01 00 00  ........ @v.....
000001ff`e8764e90  90 88 cd 00 01 00 00 00-04 00 00 00 00 00 00 00  ................
000001ff`e8764ea0  f0 05 98 e6 ff 01 00 00-00 00 00 00 00 00 00 00  ................
000001ff`e8764eb0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
000001ff`e8764ec0  00 00 00 00 00 00 00 00-20 40 76 e8 ff 01 00 00  ........ @v.....
0:007> dw rax
000001ff`e8764e50  0001 0d0e 000a 02a2 02a3 02a4 02a6 02a7
000001ff`e8764e60  02a9 02a1 02a5 02a8 02aa 00fd 00fd 00fd
000001ff`e8764e70  00fd 00fd 00fd 00fd 00fd 00fd 00fd 00fd
000001ff`e8764e80  00fd 00fd 00fd 00fd 4020 e876 01ff 0000
000001ff`e8764e90  8890 00cd 0001 0000 0004 0000 0000 0000
000001ff`e8764ea0  05f0 e698 01ff 0000 0000 0000 0000 0000
000001ff`e8764eb0  0000 0000 0000 0000 0000 0000 0000 0000
000001ff`e8764ec0  0000 0000 0000 0000 4020 e876 01ff 0000
0:007> u
FontCreator!_dbk_fcall_wrapper+0xfadf52:
00000000`01a2c262 0fb7444806      movzx   eax,word ptr [rax+rcx*2+6]
00000000`01a2c267 8985a8000000    mov     dword ptr [rbp+0A8h],eax
00000000`01a2c26d 488b85e0000000  mov     rax,qword ptr [rbp+0E0h]
00000000`01a2c274 488b4030        mov     rax,qword ptr [rax+30h]
00000000`01a2c278 488b4820        mov     rcx,qword ptr [rax+20h]
00000000`01a2c27c 8b95ac000000    mov     edx,dword ptr [rbp+0ACh]
00000000`01a2c282 e8597e2800      call    FontCreator!_dbk_fcall_wrapper+0x1235dd0 (00000000`01cb40e0)
00000000`01a2c287 84c0            test    al,al
0:007> kb
 # RetAddr               : Args to Child                                                           : Call Site
00 00000000`01a2b580     : 000001ff`e7b49a10 000001ff`e8520590 00000000`00000001 00000056`17b7efc0 : FontCreator!_dbk_fcall_wrapper+0xfadf52
01 00000000`01a4c7fe     : 000001ff`e7b499b0 000001ff`00000000 000001ff`d7b0b080 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0xfad270
02 00000000`01a4d36a     : 000001ff`e2496140 000001ff`e8520590 000001ff`e989e000 00000000`00000002 : FontCreator!_dbk_fcall_wrapper+0xfce4ee
03 00000000`01a4aa87     : 000001ff`e2496140 000001ff`e8520590 000001ff`e989e000 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0xfcf05a
04 00000000`0229132e     : 000001ff`e2496140 00000000`00000001 000001ff`d7b0b080 00000046`45444704 : FontCreator!_dbk_fcall_wrapper+0xfcc777
05 00000000`02290846     : 000001ff`e9250150 000001ff`f7155e90 000001ff`d7bbe390 000001ff`f71559b0 : FontCreator!_dbk_fcall_wrapper+0x181301e
06 00000000`0228ff88     : 000001ff`e9250150 000001ff`e8521310 00000000`00000000 00007ffa`bb0c1b00 : FontCreator!_dbk_fcall_wrapper+0x1812536
07 00000000`0229481d     : 000001ff`e9250150 000001ff`e8521310 000001ff`b5e4ef00 3fdc0ada`ad87e4a5 : FontCreator!_dbk_fcall_wrapper+0x1811c78
08 00000000`01d53330     : 00000056`17b7f8c8 00000000`00b8af19 01db943d`ae19b963 01dc4bd7`119fa800 : FontCreator!_dbk_fcall_wrapper+0x181650d
09 00000000`01071406     : 000001ff`d7b24e90 000001ff`000012e8 00000000`00001204 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0x12d5020
0a 00000000`00b6c32a     : 000001ff`e87322c0 00000000`00000000 00000000`00000000 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0x5f30f6
0b 00000000`00c477d3     : 000001ff`e87322c0 00000000`010712f0 00000000`00000000 000001ff`d358da70 : FontCreator!_dbk_fcall_wrapper+0xee01a
0c 00000000`00a721ad     : 000001ff`e87322c0 00000000`00000000 00000000`00000000 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0x1c94c3
0d 00000000`00b6c1ff     : 000001ff`d358da60 00000000`00000000 00000000`00000000 00000000`00000000 : FontCreator+0x121ad
0e 00007ffa`b9c47374     : 000001ff`d358da80 00000000`00000000 00000000`00000000 00000000`00000000 : FontCreator!_dbk_fcall_wrapper+0xedeef
0f 00007ffa`bb05cc91     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
10 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

Note that the application uses a custom allocator, so the page heap is unable to mark the immediate memory region, leading to a crash when non-reserved memory is read.

Exploiting this vulnerability allows for the reading of arbitrary memory within the process, potentially disclosing sensitive information.

TIMELINE

2025-03-25 - Vendor Disclosure
2025-05-29 - Vendor Patch Release
2025-06-02 - Public Release

Credit

Discovered by KPC of Cisco Talos.