Talos Vulnerability Report

TALOS-2024-2002

Adobe Acrobat Reader Font gvar TupleVariation Data Out-Of-Bounds Read Vulnerability

August 13, 2024
CVE Number

CVE-2024-41832

SUMMARY

An out-of-bounds read vulnerability exists in CoolType, a font processing framework used by Adobe Acrobat Reader 2024.002.20759.A specially crafted font file embedded into a PDF can trigger an out of bounds memory read which can lead to disclosure of sensitive information and aid further exploitation. 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.

Adobe Acrobat Reader 2024.002.20759

PRODUCT URLS

Acrobat Reader - https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html

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

Adobe Acrobat Reader is one of the most popular and feature-rich PDF readers on the market. It has a large user base and is usually a default PDF reader on systems. It also integrates into web browsers as a plugin for rendering PDFs.

Adobe acrobat supports parsing of embedded font files in the PDF. This vulnerability is related to OpenType font format. 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, 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 occurs when the the value of the tableTag field is the string gvar, which indicates the table type is an glyph variations (gvar) table.

The gvar table contains a header followed by shared tuple records (sharedTuples) and glyph variation data tables (GlyphVariationDataTables). The structure of the gvar table header is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02             gvar_majorVersion
0x02    0x02             gvar_minorVersion
0x04    0x02             gvar_axisCount
0x06    0x02             sharedTupleCount
0x08    0x04             sharedTuplesOffset
0x0c    0x02             gvar_glyphCount (gc)
0x0e    0x02             gvar_flags (gc_size = 4 if flags else 2)
0x10    0x04             glyphVariationDataArrayOffset
0x14    gc+1 * gc_size   glyphVariationDataOffsets 

The gvar_axisCount field gives the number of variation axes for this font. gvar_glyphCount indicates the number of glyphs present in the font. glyphVariationDataArrayOffset defines the byte offset from the beginning of this table to GlyphVariationDataTables.

The glyphVariationDataOffsets is an array that contains 2-byte or 4-byte offsets. If gvar_flags is 0, the offsets in glyphVariationDataOffsets are 2 bytes each; otherwise, they are 4 bytes. Note that if the offset size is 2 bytes, the stored value represents half of the actual offset value. Therefore, when gvar_flags is 0, the true offset value is obtained by doubling the offset value. The number of offsets present in glyphVariationDataOffsets is gvar_glyphCount + 1.

GlyphVariationDataTables is an array that contains GlyphVariationData tables.

For simplicity, consider the scenario where gvar_flags is 0, gvar_glyphCount is 3, and the values of glyphVariationDataOffsets are as follows:

glyphVariationDataOffsets = [0x04,  0x08, 0x0A, 0x0F]

In this example, the offset from the beginning of this table to the first GlyphVariationData is glyphVariationDataArrayOffset+ 0x04 * 2 and the size of the first GlyphVariationData (namely GlyphVariationData_size) is 0x08 (0x08*2- 0x04*2= 0x08 ). Here, GlyphVariationData_size indicates the size of GlyphVariationData calculated by subtracting two consecutive offsets from the glyphVariationDataOffsets array.

The structure of the GlyphVariationData table is comprised of a header followed by serialized data. The structure of the GlyphVariationData header is as follows:

Offset Size       Name
------ -------- --------------------------------------
0x00    0x02                 tupleVariationCount (tc = tupleVariationCount & 0xfff )
0x02    0x02                 tvs_dataOffset
0x04    total_tvh_size       TupleVariationHeaders 

The low 12 bits of tupleVariationCount indicates the number of tuple variation tables for this glyph. tvs_dataOffset indicates the offset from the start of the GlyphVariationData table to the serialized data. The TupleVariationHeaders contains an array of TupleVariationHeader.

The total number of TupleVariationHeader present in TupleVariationHeaders is indicated by tc. Here, total_tvh_size is the sum of the size of each TupleVariationHeader like (total_tvh_size = tvh_size_1 + tvh_size_2 + ... + tvh_size_tc ). tvh_size_1 is the size of the first TupleVariationHeader, tvh_size_2 is the size of the second TupleVariationHeader, and so on.

The structure of TupleVariationHeader is as follows:

Offset Size   Name
------ ----- --------------------------------------
0x00    0x02             tvh_variationDataSize
0x02    0x02             tvh_tupleIndex

Note that TupleVariationHeader contains other optional fields which are omitted here for brevity.

tvh_variationDataSize indicates the size of a serialized data block. The size of TupleVariationHeader (tvh_size) is variable. It can be calculated using the following python pseudo code:

def get_TupleVariationHeader_size(tvh_tupleIndex, gvar_axisCount):
    size = 4
    if (tvh_tupleIndex & 0x8000) != 0:
        size += axisCount * 2
    if (tvh_tupleIndex & 0x4000) != 0:
        size += axisCount * 4
    return size

In our case, the vulnerable GlyphVariationData contains the following data:

af132f70  80 02 00 0c 00 57 00 01-00 57 00 00 00 01 fb fd  .....W...W......
af132f80  83 26 fb f7 f9 d5 f0 ef-ef ef ec ea eb ec ec ec  .&..............
af132f90  ef f4 f7 ee f7 f9 fb fd-fd fd fb f9 f7 ee ee f9  ................

Here, the value of tupleVariationCount is 0x8002. But the low 12 bits of tupleVariationCount indicates the number of tuple variation tables for this glyph. It means TupleVariationHeaders contains two TupleVariationHeader and the values of each TupleVariationHeader are as follows:

TupleVariationHeader_1 
    tvh_variationDataSize_1 = 0x57
    tvh_tupleIndex_1 =  0x01
    tvh_size_1    =  4

TupleVariationHeader_2
    tvh_variationDataSize_2 = 0x57
    tvh_tupleIndex_2 =  0x00
    tvh_size_2    =  4

Here, total_tvh_size is 0x08 (tvh_size_1 + tvh_size_2). The value of tvh_size_1 and tvh_size_2 is calculated using the function get_TupleVariationHeader_size.

After the GlyphVariationData table header, a block of serialized data is present. A serialized data block begins with the optional shared point number data (shared-point-numbers) followed by the variation data for the tuple variation tables (per-tuple-variation-table). The optional shared-point-numbers data is present when (tupleVariationCount & 0x8000) is non-zero. The shared-point-numbers data is represented as packed point numbers.

The packed point numbers are stored as a count followed by one or more runs of point number data. The count value (namely ppn_total_count) can be calculated using the following python pseudo-code:

def get_total_packed_point_number(shared_point_number):
    total_count = 0

    if shared_point_number[0] & 0x80:
        total_count =  shared_point_number[1] | ((shared_point_number[0] & 0x7F) << 8)
    else:
        total_count =  shared_point_number[0]

    return total_count

As we can observe from the get_total_packed_point_number method, the count may be stored in one or two bytes, so this vulnerability occurs when the following condition is satisfied:

if shared_point_number[0] & 0x80:
	GlyphVariationData_size <  tvs_dataOffset + ppn_total_count + 2 + tvh_variationDataSize_1 + tvh_variationDataSize_2 + .. + tvh_variationDataSize_n 
else:
	GlyphVariationData_size <  tvs_dataOffset + ppn_total_count + 1 + tvh_variationDataSize_1 + tvh_variationDataSize_2 + .. + tvh_variationDataSize_n 

Here, tvh_variationDataSize_1 is the size of the first per-tuple-variation-table, tvh_variationDataSize_2 is the size of the second per-tuple-variation-table, and so on. The number of per-tuple-variation-table present in GlyphVariationData is indicated by tc.

In our Poc, the vulnerability occurs when reading the 0x1D GlyphVariationData table. We can observe the following in the debugger (with PageHeap enabled):

0:000> g
eax=ae0f2d20 ebx=af126fb0 ecx=0000036b edx=b01a001c esi=6e4b50b0 edi=0000001c
eip=6e575bcf esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
CoolType!CTCleanup+0x5173f:
6e575bcf 8d3cbd14000000  lea     edi,[edi*4+14h]                        ; <------------- (1)
0:000> p
Time Travel Position: 42947D:1080
eax=ae0f2d20 ebx=af126fb0 ecx=0000036b edx=b01a001c esi=6e4b50b0 edi=00000084
eip=6e575bd6 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
CoolType!CTCleanup+0x51746:
6e575bd6 57              push    edi
0:000> p
Time Travel Position: 42947D:1081
eax=ae0f2d20 ebx=af126fb0 ecx=0000036b edx=b01a001c esi=6e4b50b0 edi=00000084
eip=6e575bd7 esp=00dfb8fc ebp=00dfb93c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
CoolType!CTCleanup+0x51747:
6e575bd7 ff750c          push    dword ptr [ebp+0Ch]  ss:002b:00dfb948=00dfb968
0:000> pc
Time Travel Position: 42947D:1084
eax=ae0f2d20 ebx=af126fb0 ecx=6e4b50b0 edx=b01a001c esi=6e4b50b0 edi=00000084
eip=6e575bdd esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
CoolType!CTCleanup+0x5174d:
6e575bdd ff15ac266e6e    call    dword ptr [CoolType!CTGetVersion+0x15089c (6e6e26ac)] ds:002b:6e6e26ac=77c088e0
0:000> p
Time Travel Position: 42947D:1090
eax=0dc96a16 ebx=af126fb0 ecx=6e4b50b0 edx=00400000 esi=6e4b50b0 edi=00000084
eip=6e575be3 esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200247
CoolType!CTCleanup+0x51753:
6e575be3 ffd6            call    esi {CoolType!CTInit+0x21a60 (6e4b50b0)}   ; <---------------- (2)
0:000> p
Time Travel Position: 42947D:10AF
eax=00000426 ebx=af126fb0 ecx=00000026 edx=b01a5f90 esi=6e4b50b0 edi=00000084
eip=6e575be5 esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
CoolType!CTCleanup+0x51755:
6e575be5 8b7318          mov     esi,dword ptr [ebx+18h] ds:002b:af126fc8=6e4b50b0 ; <---------------- (3)
0:000> pc
Time Travel Position: 42947D:10B7
eax=00000426 ebx=af126fb0 ecx=6e4b50b0 edx=b01a5f90 esi=6e4b50b0 edi=00000084
eip=6e575bf8 esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
CoolType!CTCleanup+0x51768:
6e575bf8 ff15ac266e6e    call    dword ptr [CoolType!CTGetVersion+0x15089c (6e6e26ac)] ds:002b:6e6e26ac=77c088e0
0:000> p
Time Travel Position: 42947D:10C3
eax=0dc96a16 ebx=af126fb0 ecx=6e4b50b0 edx=00400000 esi=6e4b50b0 edi=00000084
eip=6e575bfe esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200247
CoolType!CTCleanup+0x5176e:
6e575bfe ffd6            call    esi {CoolType!CTInit+0x21a60 (6e4b50b0)}
0:000> p
Time Travel Position: 42947D:10E2
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=00000084
eip=6e575c00 esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200206
CoolType!CTCleanup+0x51770:
6e575c00 83c40c          add     esp,0Ch                                        ; <---------------- (4)
0:000> p
Time Travel Position: 42947D:10E3
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=00000084
eip=6e575c03 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
CoolType!CTCleanup+0x51773:
6e575c03 8bf8            mov     edi,eax
0:000> p
Time Travel Position: 42947D:10E4
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=000004b2
eip=6e575c05 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
CoolType!CTCleanup+0x51775:
6e575c05 eb3d            jmp     CoolType!CTCleanup+0x517b4 (6e575c44)
0:000> p
Time Travel Position: 42947D:10E5
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=000004b2
eip=6e575c44 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
CoolType!CTCleanup+0x517b4:
6e575c44 2b7df8          sub     edi,dword ptr [ebp-8] ss:002b:00dfb934=00000426 ;<----------------- (5)
0:000> p
Time Travel Position: 42947D:10E6
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=0000008c
eip=6e575c47 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200212
CoolType!CTCleanup+0x517b7:
6e575c47 897df4          mov     dword ptr [ebp-0Ch],edi ss:002b:00dfb930=00000050
0:000> p
eax=000004b2 ebx=af126fb0 ecx=000000b2 edx=b01a5f90 esi=6e4b50b0 edi=0000008c
eip=6e575c4a esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200212
CoolType!CTCleanup+0x517ba:
6e575c4a 0f846e010000    je      CoolType!CTCleanup+0x5192e (6e575dbe)   [br=0]
[...]
0:000> p
Time Travel Position: 42947D:1103
eax=00015070 ebx=af126fb0 ecx=6e6a4630 edx=11004040 esi=6e6a4630 edi=0000008c
eip=6e575c5e esp=00dfb8fc ebp=00dfb93c iopl=0         nv up ei pl nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200217
CoolType!CTCleanup+0x517ce:
6e575c5e 59              pop     ecx
0:000> p
Time Travel Position: 42947D:1104
eax=00015070 ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e6a4630 edi=0000008c
eip=6e575c5f esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei pl nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200217
CoolType!CTCleanup+0x517cf:
6e575c5f 3bf8            cmp     edi,eax                                              ; <------------------ (6)
0:000> p
Time Travel Position: 42947D:1105
eax=00015070 ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e6a4630 edi=0000008c
eip=6e575c61 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517d1:
6e575c61 0f8757010000    ja      CoolType!CTCleanup+0x5192e (6e575dbe)   [br=0]

At (1), the value of edi serves as an index, determining which entry of the GlyphVariationData table will be accessed (the index values start at 0). The method, called at (2), reads the offsets from the glyphVariationDataOffsets. eax at (3) and (4) contains 2 consecutive offset values. Here, gvar_flags is 1. GlyphVariationData_size is calculated at (5) and its value is 0x8c. At (6), a check is performed to ensure GlyphVariationData_size is smaller than tableLength.

0:000> p
Time Travel Position: 42947D:1109
eax=0000008c ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e7b59fc edi=ae0f2d20
eip=6e575c70 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e0:
6e575c70 50              push    eax                                  ;<---------------------------- (7)
0:000> p
Time Travel Position: 42947D:110A
eax=0000008c ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e7b59fc edi=ae0f2d20
eip=6e575c71 esp=00dfb8fc ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e1:
6e575c71 894708          mov     dword ptr [edi+8],eax ds:002b:ae0f2d28=00000000
0:000> p
Time Travel Position: 42947D:110B
eax=0000008c ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e7b59fc edi=ae0f2d20
eip=6e575c74 esp=00dfb8fc ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e4:
6e575c74 56              push    esi
0:000> p
Time Travel Position: 42947D:110C
eax=0000008c ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e7b59fc edi=ae0f2d20
eip=6e575c75 esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e5:
6e575c75 8b36            mov     esi,dword ptr [esi]  ds:002b:6e7b59fc=6e4b1510
0:000> p
Time Travel Position: 42947D:110D
eax=0000008c ebx=af126fb0 ecx=af126fb0 edx=11004040 esi=6e4b1510 edi=ae0f2d20
eip=6e575c77 esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e7:
6e575c77 8bce            mov     ecx,esi
0:000> p
Time Travel Position: 42947D:110E
eax=0000008c ebx=af126fb0 ecx=6e4b1510 edx=11004040 esi=6e4b1510 edi=ae0f2d20
eip=6e575c79 esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x517e9:
6e575c79 ff15ac266e6e    call    dword ptr [CoolType!CTGetVersion+0x15089c (6e6e26ac)] ds:002b:6e6e26ac=77c088e0
0:000> p
Time Travel Position: 42947D:111A
eax=0dc962a2 ebx=af126fb0 ecx=6e4b1510 edx=00100004 esi=6e4b1510 edi=ae0f2d20
eip=6e575c7f esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200247
CoolType!CTCleanup+0x517ef:
6e575c7f ffd6            call    esi {CoolType!CTInit+0x1dec0 (6e4b1510)}   ;<---------------------------- (8)
0:000> p
Time Travel Position: 429481:EFC
eax=af132f70 ebx=af126fb0 ecx=0000008c edx=00000000 esi=6e4b1510 edi=ae0f2d20
eip=6e575c81 esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200282
CoolType!CTCleanup+0x517f1:
6e575c81 894704          mov     dword ptr [edi+4],eax ds:002b:ae0f2d24=00000000
0:000> dd eax                                                              ;<---------------------------- (9)
af132f70  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132f80  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132f90  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132fa0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132fb0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132fc0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132fd0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132fe0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0:000> dd eax  +70
af132fe0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
af132ff0  c0c0c0c0 c0c0c0c0 c0c0c0c0 d0d0d0d0
af133000  eeeeeeed aa1f3514 00000000 00000000
af133010  00000000 00000000 00000000 00000000
af133020  00000000 00000000 00000000 00000000
af133030  00000000 00000000 00000000 00000000
af133040  00000000 00000000 00000000 00000000
af133050  00000000 00000000 00000000 00000000

[...]

0:000> p
Time Travel Position: 429481:F41
eax=b01a5f90 ebx=af126fb0 ecx=00013e82 edx=00100004 esi=6e4b15a0 edi=ae0f2d20
eip=6e575cd3 esp=00dfb900 ebp=00dfb93c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200286
CoolType!CTCleanup+0x51843:
6e575cd3 ff75d4          push    dword ptr [ebp-2Ch]  ss:002b:00dfb910=0000008c
0:000> 
Time Travel Position: 429481:F42
eax=b01a5f90 ebx=af126fb0 ecx=00013e82 edx=00100004 esi=6e4b15a0 edi=ae0f2d20
eip=6e575cd6 esp=00dfb8fc ebp=00dfb93c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200286
CoolType!CTCleanup+0x51846:
6e575cd6 ff75d0          push    dword ptr [ebp-30h]  ss:002b:00dfb90c=b01a717e
0:000> 
Time Travel Position: 429481:F43
eax=b01a5f90 ebx=af126fb0 ecx=00013e82 edx=00100004 esi=6e4b15a0 edi=ae0f2d20
eip=6e575cd9 esp=00dfb8f8 ebp=00dfb93c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200286
CoolType!CTCleanup+0x51849:
6e575cd9 ff75f4          push    dword ptr [ebp-0Ch]  ss:002b:00dfb930=0000008c
0:000> 
before calling memcpy to  af132fd4
Time Travel Position: 429481:F44
eax=b01a5f90 ebx=af126fb0 ecx=00013e82 edx=00100004 esi=6e4b15a0 edi=ae0f2d20
eip=6e575cdc esp=00dfb8f4 ebp=00dfb93c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200286
CoolType!CTCleanup+0x5184c:
6e575cdc ff7704          push    dword ptr [edi+4]    ds:002b:ae0f2d24=af132f70
0:000> 
before calling memcpy to  af132fd4
0:000> p
Time Travel Position: 429481:F45
eax=b01a5f90 ebx=af126fb0 ecx=00013e82 edx=00100004 esi=6e4b15a0 edi=ae0f2d20
eip=6e575cdf esp=00dfb8f0 ebp=00dfb93c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200286
CoolType!CTCleanup+0x5184f:
6e575cdf e8ca120000      call    CoolType!CTCleanup+0x52b1e (6e576fae)     ; <--------------- (10)
0:000> p
Time Travel Position: 429481:FF8
eax=00000000 ebx=af126fb0 ecx=00000000 edx=0000008c esi=6e4b15a0 edi=ae0f2d20
eip=6e575ce4 esp=00dfb8f0 ebp=00dfb93c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x51854:
6e575ce4 8b7324          mov     esi,dword ptr [ebx+24h] ds:002b:af126fd4=6e4b1d50
0:000> dd af132f70                                                       ; <--------------- (11)
af132f70  0c000280 01005700 00005700 fdfb0100
af132f80  f7fb2683 eff0d5f9 eaecefef ecececeb
af132f90  eef7f4ef fdfbf9f7 f9fbfdfd f9eeeef7
af132fa0  fffffffc 00eef9fc 038181ec 0209f7fa
af132fb0  05020a83 01010408 fefcfd00 f11381ff
af132fc0  fbf6f1f1 0b06fffc fcfc0b0b 0a0805fc
af132fd0  830f0f0f 83050801 090d0926 19191711
af132fe0  1e1f1e19 191c1c1c 0d1a0d12 4505070b

The malloc function is called at (8) and the size argument of malloc comes from eax at (7), which is equal to GlyphVariationData_size. This malloc creates the vulnerable buffer and its value is examined at (9). The memcpy is called at (10) to copy GlyphVariationData to the vulnerable buffer. The vulnerable buffer content can be observed at (11).

0:000> g
Breakpoint 9 hit
Time Travel Position: 42948D:D65
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552d9d esp=00dfb7d4 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e90d:
6e552d9d ff75c8          push    dword ptr [ebp-38h]  ss:002b:00dfb840=00000057
0:000> p
Time Travel Position: 42948D:D66
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552da0 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e910:
6e552da0 85ff            test    edi,edi
0:000> p
Time Travel Position: 42948D:D67
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552da2 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e912:
6e552da2 897df0          mov     dword ptr [ebp-10h],edi ss:002b:00dfb868=00000001
0:000> p
Time Travel Position: 42948D:D68
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552da5 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e915:
6e552da5 8bc3            mov     eax,ebx
0:000> p
Time Travel Position: 42948D:D69
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552da7 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e917:
6e552da7 0f45c7          cmovne  eax,edi
0:000> p
Time Travel Position: 42948D:D6A
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552daa esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91a:
6e552daa 50              push    eax
0:000> p
Time Travel Position: 42948D:D6B
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552dab esp=00dfb7cc ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91b:
6e552dab ff75f4          push    dword ptr [ebp-0Ch]  ss:002b:00dfb86c=0000008c
0:000> p
Time Travel Position: 42948D:D6C
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552dae esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91e:
6e552dae 894598          mov     dword ptr [ebp-68h],eax ss:002b:00dfb810=00dfb860
0:000> p
Time Travel Position: 42948D:D6D
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552db1 esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e921:
6e552db1 8d45ec          lea     eax,[ebp-14h]
0:000> p
Time Travel Position: 42948D:D6E
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552db4 esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e924:
6e552db4 50              push    eax
0:000> dd eax L3
00dfb864  af132f7d 00000000 0000008c
0:000> db af132f7d
af132f7d  01 fb fd 83 26 fb f7 f9-d5 f0 ef ef ef ec ea eb  ....&...........
af132f8d  ec ec ec ef f4 f7 ee f7-f9 fb fd fd fd fb f9 f7  ................
af132f9d  ee ee f9 fc ff ff ff fc-f9 ee 00 ec 81 81 03 fa  ................
af132fad  f7 09 02 83 0a 02 05 08-04 01 01 00 fd fc fe ff  ................
af132fbd  81 13 f1 f1 f1 f6 fb fc-ff 06 0b 0b 0b fc fc fc  ................
af132fcd  05 08 0a 0f 0f 0f 83 01-08 05 83 26 09 0d 09 11  ...........&....
af132fdd  17 19 19 19 1e 1f 1e 1c-1c 1c 19 12 0d 1a 0d 0b  ................
af132fed  07 05 45 05 07 03 0d 1a-1a 09 06 01 01 01 06 d0  ..E.............
0:000> p
Time Travel Position: 42948D:D6F
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552db5 esp=00dfb7c4 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e925:
6e552db5 ff75dc          push    dword ptr [ebp-24h]  ss:002b:00dfb854=6e7bebec
0:000> p
Time Travel Position: 42948D:D70
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f78 edi=00000000
eip=6e552db8 esp=00dfb7c0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e928:
6e552db8 e863320000      call    CoolType!CTCleanup+0x31b90 (6e556020)  ;<---------------------------- (12)
0:000> p
Time Travel Position: 42948D:1136
eax=00000000 ebx=0000002f ecx=6e7bebec edx=0000002f esi=af132f78 edi=00000000
eip=6e552dbd esp=00dfb7c0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e92d:
6e552dbd 83c418          add     esp,18h
0:000> g
Breakpoint 9 hit
Time Travel Position: 42948D:2066
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552d9d esp=00dfb7d4 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e90d:
6e552d9d ff75c8          push    dword ptr [ebp-38h]  ss:002b:00dfb840=00000057
0:000> p
Time Travel Position: 42948D:2067
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552da0 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e910:
6e552da0 85ff            test    edi,edi
0:000> p
Time Travel Position: 42948D:2068
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552da2 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e912:
6e552da2 897df0          mov     dword ptr [ebp-10h],edi ss:002b:00dfb868=00000000
0:000> p
Time Travel Position: 42948D:2069
eax=00000001 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552da5 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e915:
6e552da5 8bc3            mov     eax,ebx
0:000> p
Time Travel Position: 42948D:206A
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552da7 esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e917:
6e552da7 0f45c7          cmovne  eax,edi
0:000> p
Time Travel Position: 42948D:206B
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552daa esp=00dfb7d0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91a:
6e552daa 50              push    eax
0:000> p
Time Travel Position: 42948D:206C
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552dab esp=00dfb7cc ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91b:
6e552dab ff75f4          push    dword ptr [ebp-0Ch]  ss:002b:00dfb86c=0000008c
0:000> p
Time Travel Position: 42948D:206D
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552dae esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e91e:
6e552dae 894598          mov     dword ptr [ebp-68h],eax ss:002b:00dfb810=0000002f
0:000> p
Time Travel Position: 42948D:206E
eax=0000002f ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552db1 esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e921:
6e552db1 8d45ec          lea     eax,[ebp-14h]
0:000> p
Time Travel Position: 42948D:206F
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552db4 esp=00dfb7c8 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e924:
6e552db4 50              push    eax

0:000> dd eax L2
00dfb864  af132fd4 00000000
0:000> dd af132fd4
af132fd4  83050801 090d0926 19191711 1e1f1e19
af132fe4  191c1c1c 0d1a0d12 4505070b 0d030705
af132ff4  06091a1a 06010101 d0d0d0d0 eeeeeeed
af133004  aa1f3514 00000000 00000000 00000000
af133014  00000000 00000000 00000000 00000000
af133024  00000000 00000000 00000000 00000000
af133034  00000000 00000000 00000000 00000000
af133044  00000000 00000000 00000000 00000000
0:000> p
Time Travel Position: 42948D:2070
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552db5 esp=00dfb7c4 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e925:
6e552db5 ff75dc          push    dword ptr [ebp-24h]  ss:002b:00dfb854=6e7bebec
0:000> p
Time Travel Position: 42948D:2071
eax=00dfb864 ebx=0000002f ecx=00dfb800 edx=af132f70 esi=af132f7c edi=00000000
eip=6e552db8 esp=00dfb7c0 ebp=00dfb878 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
CoolType!CTCleanup+0x2e928:
6e552db8 e863320000      call    CoolType!CTCleanup+0x31b90 (6e556020)  <---------------------------- (13)
0:000> p
(16c0.1b64): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Time Travel Position: 42948E:0
eax=0000002d ebx=00dfb864 ecx=af133000 edx=0000002d esi=00000027 edi=00dfb800
eip=6e556068 esp=00dfb7a8 ebp=00dfb7b8 iopl=0         nv up ei ng nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283
CoolType!CTCleanup+0x31bd8:
6e556068 0fb601          movzx   eax,byte ptr [ecx]         ds:002b:af133000=ed <---------------------------- (14)
0:000> u
CoolType!CTCleanup+0x31bd8:
6e556068 0fb601          movzx   eax,byte ptr [ecx]
6e55606b 8945fc          mov     dword ptr [ebp-4],eax
6e55606e 8d4101          lea     eax,[ecx+1]
6e556071 8b4dfc          mov     ecx,dword ptr [ebp-4]
6e556074 8bf1            mov     esi,ecx
6e556076 8903            mov     dword ptr [ebx],eax
6e556078 83e63f          and     esi,3Fh
6e55607b 8b07            mov     eax,dword ptr [edi]
0:000> kb
 # ChildEBP RetAddr      Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 00dfb7b8 6e552dbd     6e7bebec 00dfb864 0000008c CoolType!CTCleanup+0x31bd8
01 00dfb878 6e4deca8     39236db4 6e7bd550 ae0f2bc4 CoolType!CTCleanup+0x2e92d
02 00dfb93c 6e4dd8cd     ae0f2bc4 39236db4 ae0f3c14 CoolType!CTInit+0x4b658
03 00dfba2c 6e4dd2c9     39236c18 39236d88 39236d48 CoolType!CTInit+0x4a27d
04 00dfba90 6e4dd105     39236c18 39236d88 39236d48 CoolType!CTInit+0x49c79
05 00dfbaec 6e4d7a3b     39236c18 39236d88 39236d48 CoolType!CTInit+0x49ab5
06 00dfbb60 6e4d787a     00dfbcb0 00dfbbe0 00000001 CoolType!CTInit+0x443eb
07 00dfbb7c 6e4d45b7     00dfbcb0 00dfbbe0 a47c0ed0 CoolType!CTInit+0x4422a
08 00dfbd04 6e4d3e97     a47c0ed0 6e7c4a18 00dfbef0 CoolType!CTInit+0x40f67
09 00dfbf30 6e4cd524     00dfc9f0 00dfbfbc 00000000 CoolType!CTInit+0x40847
0a 00dfca3c 6e4cb57a     0000001c 00000000 00000000 CoolType!CTInit+0x39ed4
0b 00dfcb10 6e4ca06d     ae764da8 00000032 00dfcbe4 CoolType!CTInit+0x37f2a
0c 00dfd470 6e4c9708     acf2c8fc 00dfd4a4 f3527e0a CoolType!CTInit+0x36a1d
0d 00dfd7cc 6e4c962c     acf2c8fc acf2c8e4 f35271ce CoolType!CTInit+0x360b8
0e 00dfd808 6efdc461     a912ed28 acf2c8fc acf2c8e4 CoolType!CTInit+0x35fdc
0f 00dfd81c 6efd3b1e     acf2c8e4 6efd3a80 49748e68 AGM!AGMInitialize+0x22ca1
10 00dfd830 6efce227     49748e74 6f44fa50 00000001 AGM!AGMInitialize+0x1a35e
11 00dfd854 6efdb308     00dfd880 00dfd89c 00dfd8bc AGM!AGMInitialize+0x14a67
12 00dfd868 6efdb334     00000001 9a465661 00000000 AGM!AGMInitialize+0x21b48
13 00dfd924 72e2ab2f     0a131000 3f800000 00000000 AGM!AGMInitialize+0x21b74
14 00dfd93c 00000000     00000000 00000000 a8f92ff0 verifier!AVrfDebugPageHeapFree+0xef

The method called at (12) and (13) reads the serialized data blocks. The vulnerability occurs when the second block is read by the method called at (13). Here, the aforementioned vulnerable condition is satisfied, so out-of-bound read can be observed at (14)

Using this vulnerability, it is possible to read arbitrary memory of the process. Because of complex interactions between PDF reader and font subcomponents, especially in the presence of a JavaScript engine, it is possible that sensitive contents of arbitrary memory could be disclosed, which could aid in further exploitation and exploit mitigation bypass.

TIMELINE

2024-06-06 - Vendor Disclosure
2024-08-13 - Vendor Patch Release
2024-08-13 - Public Release

Credit

Discovered by KPC of Cisco Talos.