CVE-2025-20001
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.
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
FontCreator - https://www.high-logic.com/font-editor/fontcreator
6.5 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CWE-125 - Out-of-bounds Read
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.
2025-03-25 - Vendor Disclosure
2025-05-29 - Vendor Patch Release
2025-06-02 - Public Release
Discovered by KPC of Cisco Talos.