CVE-2024-41832
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. 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.
2024-06-06 - Vendor Disclosure
2024-08-13 - Vendor Patch Release
2024-08-13 - Public Release
Discovered by KPC of Cisco Talos.