Talos Vulnerability Report

TALOS-2024-2003

Adobe Acrobat Reader Font Packed Point Numbers Out-Of-Bounds Read Vulnerability

August 13, 2024
CVE Number

CVE-2024-41835

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, including OpenType fonts. 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. Here, gc indicates gvar_glyphCount.

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.

In our case, the vulnerable GlyphVariationData contains following data:

b1544ef0  80 00 01 00 82 00 00 00-01 f7 fa 82 3a f7 f9 fc  ............:...
b1544f00  fc e9 e5 e5 e5 ea ee f1-f7 f7 f7 f2 e7 e9 f3 f5  ................
b1544f10  f8 f8 f5 02 f7 fa fa f8-f6 eb e9 f2 f7 f7 f7 f1  ................
b1544f20  ee ea e5 e5 e5 e9 f5 f3-e8 e6 e5 e6 e7 d9 ed f7  ................

Here, the value of tupleVariationCount is 0x8000 and the value of tvs_dataOffset is 0x100.

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

In our case, the vulnerable shared-point-numbers contains the following bytes:

0:002> db b1544ef0 +0x100
b1544ff0  12 12 0b 05 05 01 f8 82-00 08 00 80 02 00 0c 00  ................
b1545000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

Here, ppn_total_count calculated using get_total_packed_point_number is 0x12.

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
else:
	GlyphVariationData_size <   tvs_dataOffset + ppn_total_count + 1

Although very similar, this vulnerability is different from the one descirbed in TALOS-2024-2002 as a different method is responsible for processing packed point numbers present in other types of font tables.

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

0:002> g-
Time Travel Position: 462F79:1085
eax=a9df8d20 ebx=b158efb0 ecx=0000036d edx=af4401c9 esi=701250b0 edi=af5ed638
eip=701e5bb8 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
CoolType!CTCleanup+0x51728:
701e5bb8 0fb7fa          movzx   edi,dx
0:002> p
Time Travel Position: 462F79:1086
eax=a9df8d20 ebx=b158efb0 ecx=0000036d edx=af4401c9 esi=701250b0 edi=000001c9
eip=701e5bbb esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
CoolType!CTCleanup+0x5172b:
701e5bbb 83600400        and     dword ptr [eax+4],0  ds:002b:a9df8d24=00000000 ;<--------------- (1)

0:002> pc
Time Travel Position: 462F79:1091
eax=a9df8d20 ebx=b158efb0 ecx=701250b0 edx=af4401c9 esi=701250b0 edi=00000738
eip=701e5bdd esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
CoolType!CTCleanup+0x5174d:
701e5bdd ff15ac263570    call    dword ptr [CoolType!CTGetVersion+0x15089c (703526ac)] ds:002b:703526ac=76ff8a10
0:002> p
Time Travel Position: 462F79:109D
eax=0e024a16 ebx=b158efb0 ecx=701250b0 edx=00400000 esi=701250b0 edi=00000738
eip=701e5be3 esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
CoolType!CTCleanup+0x51753:
701e5be3 ffd6            call    esi {CoolType!CTInit+0x21a60 (701250b0)}    ;<----------------- (2)
0:002> p
Time Travel Position: 462F79:10BC
eax=000078a0 ebx=b158efb0 ecx=000000a0 edx=af442f48 esi=701250b0 edi=00000738
eip=701e5be5 esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
CoolType!CTCleanup+0x51755:
701e5be5 8b7318          mov     esi,dword ptr [ebx+18h] ds:002b:b158efc8=701250b0 ;<----------------- (3)
0:002> pc
Time Travel Position: 462F79:10C4
eax=000078a0 ebx=b158efb0 ecx=701250b0 edx=af442f48 esi=701250b0 edi=00000738
eip=701e5bf8 esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei ng nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000292
CoolType!CTCleanup+0x51768:
701e5bf8 ff15ac263570    call    dword ptr [CoolType!CTGetVersion+0x15089c (703526ac)] ds:002b:703526ac=76ff8a10
0:002> p
Time Travel Position: 462F79:10D0
eax=0e024a16 ebx=b158efb0 ecx=701250b0 edx=00400000 esi=701250b0 edi=00000738
eip=701e5bfe esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
CoolType!CTCleanup+0x5176e:
701e5bfe ffd6            call    esi {CoolType!CTInit+0x21a60 (701250b0)}    
0:002> p
Time Travel Position: 462F79:10EF
eax=000079b0 ebx=b158efb0 ecx=000000b0 edx=af442f48 esi=701250b0 edi=00000738
eip=701e5c00 esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
CoolType!CTCleanup+0x51770:
701e5c00 83c40c          add     esp,0Ch                                     ;<-----------------  (4)
0:002> p
Time Travel Position: 462F79:10F0
eax=000079b0 ebx=b158efb0 ecx=000000b0 edx=af442f48 esi=701250b0 edi=00000738
eip=701e5c03 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei ng nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000292
CoolType!CTCleanup+0x51773:
701e5c03 8bf8            mov     edi,eax
0:002> p
Time Travel Position: 462F79:10F1
eax=000079b0 ebx=b158efb0 ecx=000000b0 edx=af442f48 esi=701250b0 edi=000079b0
eip=701e5c05 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei ng nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000292
CoolType!CTCleanup+0x51775:
701e5c05 eb3d            jmp     CoolType!CTCleanup+0x517b4 (701e5c44)
0:002> p
Time Travel Position: 462F79:10F2
eax=000079b0 ebx=b158efb0 ecx=000000b0 edx=af442f48 esi=701250b0 edi=000079b0
eip=701e5c44 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei ng nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000292
CoolType!CTCleanup+0x517b4:
701e5c44 2b7df8          sub     edi,dword ptr [ebp-8] ss:002b:af5ed604=000078a0 ;<----------------- (5)
0:002> p
Time Travel Position: 462F79:10F3
eax=000079b0 ebx=b158efb0 ecx=000000b0 edx=af442f48 esi=701250b0 edi=00000110
eip=701e5c47 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
CoolType!CTCleanup+0x517b7:
701e5c47 897df4          mov     dword ptr [ebp-0Ch],edi ss:002b:af5ed600=00000050 

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 0x110.

0:002> p
Time Travel Position: 462F79:1116
eax=00000110 ebx=b158efb0 ecx=b158efb0 edx=11004040 esi=704259fc edi=a9df8d20
eip=701e5c70 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
CoolType!CTCleanup+0x517e0:
701e5c70 50              push    eax                                           ;<----------------- (6)
0:002> 
Time Travel Position: 462F79:1117
eax=00000110 ebx=b158efb0 ecx=b158efb0 edx=11004040 esi=704259fc edi=a9df8d20
eip=701e5c71 esp=af5ed5cc ebp=af5ed60c iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
CoolType!CTCleanup+0x517e1:
701e5c71 894708          mov     dword ptr [edi+8],eax ds:002b:a9df8d28=00000000
0:002> 
Time Travel Position: 462F79:1118
eax=00000110 ebx=b158efb0 ecx=b158efb0 edx=11004040 esi=704259fc edi=a9df8d20
eip=701e5c74 esp=af5ed5cc ebp=af5ed60c iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
CoolType!CTCleanup+0x517e4:
701e5c74 56              push    esi
0:002> pc
Time Travel Position: 462F79:111B
eax=00000110 ebx=b158efb0 ecx=70121510 edx=11004040 esi=70121510 edi=a9df8d20
eip=701e5c79 esp=af5ed5c8 ebp=af5ed60c iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
CoolType!CTCleanup+0x517e9:
701e5c79 ff15ac263570    call    dword ptr [CoolType!CTGetVersion+0x15089c (703526ac)] ds:002b:703526ac=76ff8a10
0:002> p
Time Travel Position: 462F79:1127
eax=0e0242a2 ebx=b158efb0 ecx=70121510 edx=00100004 esi=70121510 edi=a9df8d20
eip=701e5c7f esp=af5ed5c8 ebp=af5ed60c iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
CoolType!CTCleanup+0x517ef:
701e5c7f ffd6            call    esi {CoolType!CTInit+0x1dec0 (70121510)}     ;<----------------- (7)
0:002> p
Time Travel Position: 462F7D:F64
eax=b1544ef0 ebx=b158efb0 ecx=00000110 edx=00000000 esi=70121510 edi=a9df8d20
eip=701e5c81 esp=af5ed5c8 ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x517f1:
701e5c81 894704          mov     dword ptr [edi+4],eax ds:002b:a9df8d24=00000000
0:002> dd eax                                                               ;<----------------- (8)
b1544ef0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f00  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f10  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f20  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f30  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f40  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f50  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
b1544f60  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0

[...]
0:002> g
Time Travel Position: 462F7D:FA9
eax=af442f48 ebx=b158efb0 ecx=0000ca43 edx=00100004 esi=701215a0 edi=a9df8d20
eip=701e5cd3 esp=af5ed5d0 ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x51843:
701e5cd3 ff75d4          push    dword ptr [ebp-2Ch]  ss:002b:af5ed5e0=00000110
0:002> p
Time Travel Position: 462F7D:FAA
eax=af442f48 ebx=b158efb0 ecx=0000ca43 edx=00100004 esi=701215a0 edi=a9df8d20
eip=701e5cd6 esp=af5ed5cc ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x51846:
701e5cd6 ff75d0          push    dword ptr [ebp-30h]  ss:002b:af5ed5dc=af44b5b8
0:002> p
Time Travel Position: 462F7D:FAB
eax=af442f48 ebx=b158efb0 ecx=0000ca43 edx=00100004 esi=701215a0 edi=a9df8d20
eip=701e5cd9 esp=af5ed5c8 ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x51849:
701e5cd9 ff75f4          push    dword ptr [ebp-0Ch]  ss:002b:af5ed600=00000110
0:002> p
Time Travel Position: 462F7D:FAC
eax=af442f48 ebx=b158efb0 ecx=0000ca43 edx=00100004 esi=701215a0 edi=a9df8d20
eip=701e5cdc esp=af5ed5c4 ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x5184c:
701e5cdc ff7704          push    dword ptr [edi+4]    ds:002b:a9df8d24=b1544ef0
0:002> p
Time Travel Position: 462F7D:FAD
eax=af442f48 ebx=b158efb0 ecx=0000ca43 edx=00100004 esi=701215a0 edi=a9df8d20
eip=701e5cdf esp=af5ed5c0 ebp=af5ed60c iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x5184f:
701e5cdf e8ca120000      call    CoolType!CTCleanup+0x52b1e (701e6fae)    ;<----------------- (9)
0:002> p
Time Travel Position: 462F7D:10E6
eax=00000000 ebx=b158efb0 ecx=00000000 edx=00000110 esi=701215a0 edi=a9df8d20
eip=701e5ce4 esp=af5ed5c0 ebp=af5ed60c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
CoolType!CTCleanup+0x51854:
701e5ce4 8b7324          mov     esi,dword ptr [ebx+24h] ds:002b:b158efd4=70121d50
0:002> db b1544ef0 L110                                                   ;<----------------- (10)
b1544ef0  80 00 01 00 82 00 00 00-01 f7 fa 82 3a f7 f9 fc  ............:...
b1544f00  fc e9 e5 e5 e5 ea ee f1-f7 f7 f7 f2 e7 e9 f3 f5  ................
b1544f10  f8 f8 f5 02 f7 fa fa f8-f6 eb e9 f2 f7 f7 f7 f1  ................
b1544f20  ee ea e5 e5 e5 e9 f5 f3-e8 e6 e5 e6 e7 d9 ed f7  ................
b1544f30  f4 ee ee ee ee f4 00 e6-81 03 05 05 ff fc 82 05  ................
b1544f40  fe fd 07 07 f7 fb 82 16-fb f7 07 07 fd 00 01 fe  ................
b1544f50  fb f5 f2 fe 0e 0c 07 03-00 ff 03 f7 f7 09 05 82  ................
b1544f60  13 05 09 f7 f7 03 ff 00-03 07 0c 0e fe f3 f3 f3  ................
b1544f70  f9 fc fc ff 05 82 00 fb-3f 0e 09 01 01 01 0c 0b  ........?.......
b1544f80  07 06 21 28 28 28 21 1b-15 0e 0e 0e 15 25 21 13  ..!(((!......%!.
b1544f90  0f 0b 0d 10 fe 0d 0a 09-0b 0e 1e 21 14 0e 0e 0e  ...........!....
b1544fa0  15 1b 21 28 28 28 20 0f-12 22 25 28 26 23 38 1b  ..!((( .."%(&#8.
b1544fb0  0e 13 1b 1b 1b 1b 13 00-25 81 0c f8 f8 01 05 ff  ........%.......
b1544fc0  ff 01 03 04 f6 f6 0d 08-82 16 08 0d f6 f6 04 01  ................
b1544fd0  00 03 08 0f 13 04 eb ef-f7 fb 00 01 fb 0c 0c f3  ................
b1544fe0  f9 82 13 f9 f3 0c 0c fb-01 00 fb f7 ef eb 04 12  ................
b1544ff0  12 12 0b 05 05 01 f8 82-00 08 00 80 02 00 0c 00  ................

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

0:002> p
Time Travel Position: 462F88:92C
eax=00000100 ebx=00000042 ecx=00008000 edx=00000000 esi=b1544ef0 edi=00000110
eip=701c2a50 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
CoolType!CTCleanup+0x2e5c0:
701c2a50 6603d1          add     dx,cx
0:002> p
Time Travel Position: 462F88:92D
eax=00000100 ebx=00000042 ecx=00008000 edx=00008000 esi=b1544ef0 edi=00000110
eip=701c2a53 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e5c3:
701c2a53 0fb7c2          movzx   eax,dx
0:002> p
Time Travel Position: 462F88:92E
eax=00008000 ebx=00000042 ecx=00008000 edx=00008000 esi=b1544ef0 edi=00000110
eip=701c2a56 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e5c6:
701c2a56 8945bc          mov     dword ptr [ebp-44h],eax ss:002b:af5ed504=76ff7c34  ;<----------------- (11)
[...]

0:002> p
Time Travel Position: 462F88:938
eax=00000100 ebx=00000042 ecx=00000100 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2a7f esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
CoolType!CTCleanup+0x2e5ef:
701c2a7f 0fb7c2          movzx   eax,dx
0:002> p
Time Travel Position: 462F88:939
eax=00000100 ebx=00000042 ecx=00000100 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2a82 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
CoolType!CTCleanup+0x2e5f2:
701c2a82 0fb7d0          movzx   edx,ax
0:002> p
Time Travel Position: 462F88:93A
eax=00000100 ebx=00000042 ecx=00000100 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2a85 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
CoolType!CTCleanup+0x2e5f5:
701c2a85 8945cc          mov     dword ptr [ebp-34h],eax ss:002b:af5ed514=00000000 ;<----------------- (12)
[...]
0:002> p
Time Travel Position: 462F88:945
eax=00000000 ebx=00000042 ecx=00008000 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2aaf esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000287
CoolType!CTCleanup+0x2e61f:
701c2aaf 6685c9          test    cx,cx                                           ;<----------------- (13)
0:002> p
Time Travel Position: 462F88:946
eax=00000000 ebx=00000042 ecx=00008000 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2ab2 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e622:
701c2ab2 794d            jns     CoolType!CTCleanup+0x2e671 (701c2b01)   [br=0]  ;<----------------- (14)
0:002> p
Time Travel Position: 462F88:947
eax=00000000 ebx=00000042 ecx=00008000 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2ab4 esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e624:
701c2ab4 8b8578ffffff    mov     eax,dword ptr [ebp-88h] ss:002b:af5ed4c0=b1544ef0
0:002> p
Time Travel Position: 462F88:948
eax=b1544ef0 ebx=00000042 ecx=00008000 edx=00000100 esi=b1544ef4 edi=00000110
eip=701c2aba esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e62a:
701c2aba 8d3c02          lea     edi,[edx+eax]                                 ;<----------------- (15)
0:002> p
Time Travel Position: 462F88:949
eax=b1544ef0 ebx=00000042 ecx=00008000 edx=00000100 esi=b1544ef4 edi=b1544ff0
eip=701c2abd esp=af5ed4a8 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e62d:
701c2abd 897dec          mov     dword ptr [ebp-14h],edi ss:002b:af5ed534=af5ed60c

0:002> db edi                                                                 ;<----------------- (16)
b1544ff0  12 12 0b 05 05 01 f8 82-00 08 00 80 02 00 0c 00  ................
b1545000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545020  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545030  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545040  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545050  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
b1545060  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
0:002> pc
Time Travel Position: 462F88:956
eax=af5ed534 ebx=00000042 ecx=00000110 edx=00000100 esi=b1544ef4 edi=b1544ff0
eip=701c2ae6 esp=af5ed490 ebp=af5ed548 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
CoolType!CTCleanup+0x2e656:
701c2ae6 e844360000      call    CoolType!CTCleanup+0x31c9f (701c612f)               ;<----------------- (17)

The eax at (11) contains tupleVariationCount. The eax at (12) contains tvs_dataOffset. At (13) and (14), the application checks whether the optional shared-point-numbers is present in GlyphVariationData. Here, the optional shared-point-numbers is present. At (15), tvs_dataOffset is added to the vulnerable buffer to get to the optional shared-point-numbers. The shared-point-numbers value is examined at (16). The method called at (17) process shared-point-numbers. Here, the vulnerable condition exists. The out-of-bounds read occurs when the method tries to unpack shared-point-numbers. This can be observed at the time of the crash:

0:002> g
(760.1ddc): 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: 462F89:0
eax=00000012 ebx=0000000e ecx=b1545000 edx=0000000e esi=af5ed4d4 edi=af5ed534
eip=701c6205 esp=af5ed470 ebp=af5ed488 iopl=0         nv up ei ng nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000287
CoolType!CTCleanup+0x31d75:
701c6205 0fb601          movzx   eax,byte ptr [ecx]         ds:002b:b1545000=??
0:002> dd b1545000
b1545000  ???????? ???????? ???????? ????????
b1545010  ???????? ???????? ???????? ????????
b1545020  ???????? ???????? ???????? ????????
b1545030  ???????? ???????? ???????? ????????
b1545040  ???????? ???????? ???????? ????????
b1545050  ???????? ???????? ???????? ????????
b1545060  ???????? ???????? ???????? ????????
b1545070  ???????? ???????? ???????? ????????
0:002> u
CoolType!CTCleanup+0x31d75:
701c6205 0fb601          movzx   eax,byte ptr [ecx]
701c6208 660145fe        add     word ptr [ebp-2],ax
701c620c 8d4101          lea     eax,[ecx+1]
701c620f 8b4d08          mov     ecx,dword ptr [ebp+8]
701c6212 8907            mov     dword ptr [edi],eax
701c6214 668b45fe        mov     ax,word ptr [ebp-2]
701c6218 66890459        mov     word ptr [ecx+ebx*2],ax
701c621c 43              inc     ebx
0:002> kb
 # ChildEBP RetAddr      Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 af5ed488 701c2aeb     7042eb30 af5ed534 00000110 CoolType!CTCleanup+0x31d75
01 af5ed548 7014eca8     39046db4 7042d550 a9df8bc4 CoolType!CTCleanup+0x2e65b
02 af5ed60c 7014d8cd     a9df8bc4 39046db4 a9df9c14 CoolType!CTInit+0x4b658
03 af5ed6fc 7014d2c9     39046c18 39046d88 39046d48 CoolType!CTInit+0x4a27d
04 af5ed760 7014d105     39046c18 39046d88 39046d48 CoolType!CTInit+0x49c79
05 af5ed7bc 70147a3b     39046c18 39046d88 39046d48 CoolType!CTInit+0x49ab5
06 af5ed830 7014787a     af5ed980 af5ed8b0 00000001 CoolType!CTInit+0x443eb
07 af5ed84c 701445b7     af5ed980 af5ed8b0 aea55ed0 CoolType!CTInit+0x4422a
08 af5ed9d4 70143e97     aea55ed0 70434a18 af5edbc0 CoolType!CTInit+0x40f67
09 af5edc00 7013d524     af5ee6c0 af5edc8c 00000000 CoolType!CTInit+0x40847
0a af5ee70c 7013b57a     000001c9 00000000 00000000 CoolType!CTInit+0x39ed4
0b af5ee7e0 70139b5e     af5eea68 00000001 af5ee848 CoolType!CTInit+0x37f2a
0c af5eeb4c 7013962c     b121ef74 b121ef5c afeb612e CoolType!CTInit+0x3650e
0d af5eeb88 704bc461     a75f6cc0 b121ef74 b121ef5c CoolType!CTInit+0x35fdc
0e af5eeb9c 704b3b1e     b121ef5c 704b3a80 43981124 AGM!AGMInitialize+0x22ca1
0f af5eebb0 704ae227     43981130 7092fa50 00000001 AGM!AGMInitialize+0x1a35e
10 af5eebd4 704bb308     af5eec00 af5eec1c af5eec3c AGM!AGMInitialize+0x14a67
11 af5eebe8 704bb334     00000001 9ad3ee3d 00000000 AGM!AGMInitialize+0x21b48
12 af5eeca4 7416ab2f     07d01000 3f800000 00000000 AGM!AGMInitialize+0x21b74
13 af5eecbc 00000000     00000000 00000000 b1fd2ff0 verifier!AVrfDebugPageHeapFree+0xef

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-10 - Vendor Disclosure
2024-08-13 - Vendor Patch Release
2024-08-13 - Public Release

Credit

Discovered by KPC of Cisco Talos.