CVE-2024-41835
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.
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
Acrobat Reader - https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html
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
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 ..!((( .."%(.
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.
2024-06-10 - Vendor Disclosure
2024-08-13 - Vendor Patch Release
2024-08-13 - Public Release
Discovered by KPC of Cisco Talos.