CVE-2024-49532
An out-of-bounds read vulnerability exists in font handling code of Adobe Acrobat Reader 2024.002.21005. 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.21005
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 or 0x74727565, the font contains TrueType data. The CFF data will be present if the value of sfntVersion
is 0x4F54544F (‘OTTO). The numTables
field specifies the number of TableRecord
entries present in the font file. The structure of a TableRecord
entry is as follows:
Offset Size Name
------ ----- ----------------------------------
0x00 0x04 tableTag
0x04 0x04 tableChecksum
0x08 0x04 tableOffset
0x0C 0x04 tableLength
tableTag
is the name of TableRecord
. The tableOffset
field specifies the offset of the table from the beginning of the file. The tableLength
indicates the length of the table. The structure of each TableRecord
depends on the type table, which is defined by the tableTag
. This vulnerability 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:
d2e9afe0 00 02 00 0c 00 0d 20 01-00 07 20 00 03 02 2e 05
d2e9aff0 05 81 40 01 50 81 00 22-01 00 04 80 40 00 c6 00
Here, the value of tupleVariationCount
is 0x02. Note that the low 12 bits of tupleVariationCount
is 0 here. It means TupleVariationHeaders
contains two TupleVariationHeader
and the values of each TupleVariationHeader
are as follows:
TupleVariationHeader_1
tvh_variationDataSize_1 = 0x0d
tvh_tupleIndex_1 = 0x2001
tvh_size_1 = 4
TupleVariationHeader_2
tvh_variationDataSize_2 = 0x07
tvh_tupleIndex_2 = 0x2000
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. Here, (tupleVariationCount & 0x8000
) is zero, so shared-point-numbers
is not present.
The per-tuple-variation-table
data begins with the optional private-point-numbers
if (tvh_tupleIndex & 0x2000
) is non-zero. The private-point-numbers
data is represented as packed point numbers
.
The total length of the private-point-numbers
data can be calculated using the following python pseudo-code:
def get_total_length_of_ppn(private_point_number):
total_ppn_count = 0
if private_point_number[0] & 0x80:
total_ppn_count = (private_point_number[1] | ((private_point_number[0] & 0x7F) << 8) ) + 2
else:
total_ppn_count = private_point_number[0] + 1
return total_ppn_count
The vulnerability occurs when private-point-numbers
data is present in the per-tuple-variation-table
. The application reads the private-point-numbers
and increments the buffer by total_ppn_count
. However, when it calls a function to read the remaining data of the per-tuple-variation-table
, it incorrectly passes tvh_variationDataSize
instead of (tvh_variationDataSize - total_ppn_count
), which leads to an out-of-bounds read condition.
Note that, this vulnerability is triggered with a valid font file because the application fails to account for the size of private-point-numbers
when reading the per-tuple-variation-table
.
In our Poc, the vulnerability occurs when reading the 0x09 GlyphVariationData
table. We can observe the following in the debugger (with PageHeap enabled):
0:002> p
Time Travel Position: 9ECAC:10D6
eax=e2b04d54 ebx=e7976fb0 ecx=00000013 edx=c3860008 esi=7007caa0 edi=00000008
eip=701369fa esp=0040bfe0 ebp=0040c01c 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+0xd11ea:
701369fa 8d3c7d14000000 lea edi,[edi*2+14h] ;<---------------------------- (1)
0:002> p
Time Travel Position: 9ECAC:10D7
eax=e2b04d54 ebx=e7976fb0 ecx=00000013 edx=c3860008 esi=7007caa0 edi=00000024
eip=70136a01 esp=0040bfe0 ebp=0040c01c 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+0xd11f1:
70136a01 57 push edi
0:002> p
Time Travel Position: 9ECAC:10D8
eax=e2b04d54 ebx=e7976fb0 ecx=00000013 edx=c3860008 esi=7007caa0 edi=00000024
eip=70136a02 esp=0040bfdc ebp=0040c01c 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+0xd11f2:
70136a02 ff750c push dword ptr [ebp+0Ch] ss:002b:0040c028=0040c048
0:002> p
Time Travel Position: 9ECAC:10D9
eax=e2b04d54 ebx=e7976fb0 ecx=00000013 edx=c3860008 esi=7007caa0 edi=00000024
eip=70136a05 esp=0040bfd8 ebp=0040c01c 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+0xd11f5:
70136a05 8bce mov ecx,esi
0:002> p
Time Travel Position: 9ECAC:10DA
eax=e2b04d54 ebx=e7976fb0 ecx=7007caa0 edx=c3860008 esi=7007caa0 edi=00000024
eip=70136a07 esp=0040bfd8 ebp=0040c01c 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+0xd11f7:
70136a07 53 push ebx
0:002> p
Time Travel Position: 9ECAC:10DB
eax=e2b04d54 ebx=e7976fb0 ecx=7007caa0 edx=c3860008 esi=7007caa0 edi=00000024
eip=70136a08 esp=0040bfd4 ebp=0040c01c 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+0xd11f8:
70136a08 ff15ac262a70 call dword ptr [CoolType!CTGetVersion+0x14faac (702a26ac)] ds:002b:702a26ac={ntdll!LdrpValidateUserCallTarget (76ff8a10)}
0:002>
Time Travel Position: 9ECAC:10E7
eax=0e00f954 ebx=e7976fb0 ecx=7007caa0 edx=00100000 esi=7007caa0 edi=00000024
eip=70136a0e esp=0040bfd4 ebp=0040c01c 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+0xd11fe:
70136a0e ffd6 call esi {CoolType!CTCleanup+0x17290 (7007caa0)} ; <---------------- (2)
0:002>
Time Travel Position: 9ECAC:10FE
eax=000009d6 ebx=e7976fb0 ecx=000000d6 edx=00000024 esi=7007caa0 edi=00000024
eip=70136a10 esp=0040bfd4 ebp=0040c01c 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+0xd1200:
70136a10 8b730c mov esi,dword ptr [ebx+0Ch] ds:002b:e7976fbc=7007caa0 ; <---------------- (3)
[...]
0:002>
Time Travel Position: 9ECAC:1107
eax=00000026 ebx=e7976fb0 ecx=7007caa0 edx=00000024 esi=7007caa0 edi=00000024
eip=70136a25 esp=0040bfd4 ebp=0040c01c 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+0xd1215:
70136a25 ff15ac262a70 call dword ptr [CoolType!CTGetVersion+0x14faac (702a26ac)] ds:002b:702a26ac={ntdll!LdrpValidateUserCallTarget (76ff8a10)}
0:002>
Time Travel Position: 9ECAC:1113
eax=0e00f954 ebx=e7976fb0 ecx=7007caa0 edx=00100000 esi=7007caa0 edi=00000024
eip=70136a2b esp=0040bfd4 ebp=0040c01c 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+0xd121b:
70136a2b ffd6 call esi {CoolType!CTCleanup+0x17290 (7007caa0)}
0:002>
Time Travel Position: 9ECAC:112A
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=00000024
eip=70136a2d esp=0040bfd4 ebp=0040c01c 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+0xd121d:
70136a2d 8bf8 mov edi,eax ; <---------------- (4)
0:002> p
Time Travel Position: 9ECAC:112B
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=000009e6
eip=70136a2f esp=0040bfd4 ebp=0040c01c 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+0xd121f:
70136a2f 83c40c add esp,0Ch
0:002> p
Time Travel Position: 9ECAC:112C
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=000009e6
eip=70136a32 esp=0040bfe0 ebp=0040c01c iopl=0 nv up ei pl nz ac po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212
CoolType!CTCleanup+0xd1222:
70136a32 03ff add edi,edi ;<--------------------- (5)
0:002>
Time Travel Position: 9ECAC:112D
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=000013cc
eip=70136a34 esp=0040bfe0 ebp=0040c01c 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+0xd1224:
70136a34 2b7df8 sub edi,dword ptr [ebp-8] ss:002b:0040c014=000013ac ;<----------------- (6)
0:002>
Time Travel Position: 9ECAC:112E
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=00000020
eip=70136a37 esp=0040bfe0 ebp=0040c01c 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+0xd1227:
70136a37 897df4 mov dword ptr [ebp-0Ch],edi ss:002b:0040c010=00000050
0:002> p
Time Travel Position: 9ECAC:112F
eax=000009e6 ebx=e7976fb0 ecx=000000e6 edx=00000026 esi=7007caa0 edi=00000020
eip=70136a3a esp=0040bfe0 ebp=0040c01c 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+0xd122a:
70136a3a 0f846e010000 je CoolType!CTCleanup+0xd139e (70136bae) [br=0]
[...]
0:002> p
Time Travel Position: 9ECAC:114C
eax=000022ae ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=70264880 edi=00000020
eip=70136a4f esp=0040bfe0 ebp=0040c01c iopl=0 nv up ei pl nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000217
CoolType!CTCleanup+0xd123f:
70136a4f 3bf8 cmp edi,eax ;<------------------(7)
0:002> p
Time Travel Position: 9ECAC:114D
eax=000022ae ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=70264880 edi=00000020
eip=70136a51 esp=0040bfe0 ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1241:
70136a51 0f8757010000 ja CoolType!CTCleanup+0xd139e (70136bae) [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 two consecutive offset values. Here, gvar_flags
is 0, so the actual offset value is obtained by doubling the offset value, as shown at (5)
. GlyphVariationData_size
is calculated at (6)
and its value is 0x20. At (7)
, a check is performed to ensure GlyphVariationData_size
is smaller than tableLength
.
0:002> p
Time Travel Position: 9ECAC:1151
eax=00000020 ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=703759fc edi=e2b04d54
eip=70136a60 esp=0040bfe0 ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1250:
70136a60 50 push eax ;<---------------------------- (8)
0:002> p
Time Travel Position: 9ECAC:1152
eax=00000020 ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=703759fc edi=e2b04d54
eip=70136a61 esp=0040bfdc ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1251:
70136a61 894708 mov dword ptr [edi+8],eax ds:002b:e2b04d5c=00000000
0:002> p
Time Travel Position: 9ECAC:1153
eax=00000020 ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=703759fc edi=e2b04d54
eip=70136a64 esp=0040bfdc ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1254:
70136a64 56 push esi
0:002> p
Time Travel Position: 9ECAC:1154
eax=00000020 ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=703759fc edi=e2b04d54
eip=70136a65 esp=0040bfd8 ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1255:
70136a65 8b36 mov esi,dword ptr [esi] ds:002b:703759fc=70077eb0
0:002> p
Time Travel Position: 9ECAC:1155
eax=00000020 ebx=e7976fb0 ecx=e7976fb0 edx=01010010 esi=70077eb0 edi=e2b04d54
eip=70136a67 esp=0040bfd8 ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1257:
70136a67 8bce mov ecx,esi
0:002> p
Time Travel Position: 9ECAC:1156
eax=00000020 ebx=e7976fb0 ecx=70077eb0 edx=01010010 esi=70077eb0 edi=e2b04d54
eip=70136a69 esp=0040bfd8 ebp=0040c01c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
CoolType!CTCleanup+0xd1259:
70136a69 ff15ac262a70 call dword ptr [CoolType!CTGetVersion+0x14faac (702a26ac)] ds:002b:702a26ac={ntdll!LdrpValidateUserCallTarget (76ff8a10)}
0:002> p
Time Travel Position: 9ECAC:1162
eax=0e00efd6 ebx=e7976fb0 ecx=70077eb0 edx=01440000 esi=70077eb0 edi=e2b04d54
eip=70136a6f esp=0040bfd8 ebp=0040c01c 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+0xd125f:
70136a6f ffd6 call esi {CoolType!CTCleanup+0x126a0 (70077eb0)} ;<---------------------------- (9)
0:002> p
Time Travel Position: 9ECB0:EEF
eax=d2e9afe0 ebx=e7976fb0 ecx=00000020 edx=00000000 esi=70077eb0 edi=e2b04d54
eip=70136a71 esp=0040bfd8 ebp=0040c01c iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
CoolType!CTCleanup+0xd1261:
70136a71 894704 mov dword ptr [edi+4],eax ds:002b:e2b04d58=00000000
0:002> dd eax ;<---------------------------- (10)
d2e9afe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
d2e9aff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
d2e9b000 ???????? ???????? ???????? ????????
[...]
0:002> p
Time Travel Position: 9ECB0:F36
eax=c3866d50 ebx=e7976fb0 ecx=00000e4e edx=00014000 esi=70077f80 edi=e2b04d54
eip=70136ac9 esp=0040bfd8 ebp=0040c01c iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
CoolType!CTCleanup+0xd12b9:
70136ac9 ff75f4 push dword ptr [ebp-0Ch] ss:002b:0040c010=00000020
0:002> p
Time Travel Position: 9ECB0:F37
eax=c3866d50 ebx=e7976fb0 ecx=00000e4e edx=00014000 esi=70077f80 edi=e2b04d54
eip=70136acc esp=0040bfd4 ebp=0040c01c iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
CoolType!CTCleanup+0xd12bc:
70136acc ff7704 push dword ptr [edi+4] ds:002b:e2b04d58=d2e9afe0
0:002> p
Time Travel Position: 9ECB0:F38
eax=c3866d50 ebx=e7976fb0 ecx=00000e4e edx=00014000 esi=70077f80 edi=e2b04d54
eip=70136acf esp=0040bfd0 ebp=0040c01c iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
CoolType!CTCleanup+0xd12bf:
70136acf e8ca120000 call CoolType!CTCleanup+0xd258e (70137d9e) ;<----------------------- (11)
0:002> p
Time Travel Position: 9ECB0:F72
eax=00000000 ebx=e7976fb0 ecx=00000000 edx=00000000 esi=70077f80 edi=e2b04d54
eip=70136ad4 esp=0040bfd0 ebp=0040c01c 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+0xd12c4:
70136ad4 8b7324 mov esi,dword ptr [ebx+24h] ds:002b:e7976fd4=70078fa0
0:002> db d2e9afe0 ;<----------------------- (12)
d2e9afe0 00 02 00 0c 00 0d 20 01-00 07 20 00 03 02 2e 05 ...... ... .....
d2e9aff0 05 81 40 01 50 81 00 22-01 00 04 80 40 00 c6 00 ..@.P.."....@...
d2e9b000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
The malloc
function is called at (9)
, and the size
argument of malloc
comes from eax
at (8)
, which is equal to GlyphVariationData_size
. This malloc
creates the vulnerable buffer, and its value is examined at (10)
. The memcpy
function is called at (11)
to copy GlyphVariationData
to the vulnerable buffer. The content of the vulnerable buffer can be observed at (11)
.
eax=00010000 ebx=00000035 ecx=00000006 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146d2 esp=0040bebc ebp=0040bf58 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+0xaeec2:
701146d2 8b45d8 mov eax,dword ptr [ebp-28h] ss:002b:0040bf30=00000019
0:002> p
Time Travel Position: 9ECC1:1674
eax=00000019 ebx=00000035 ecx=00000006 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146d5 esp=0040bebc ebp=0040bf58 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+0xaeec5:
701146d5 0fb7c0 movzx eax,ax ; <------------------------------------------- (13)
0:002> p
Time Travel Position: 9ECC1:1675
eax=00000019 ebx=00000035 ecx=00000006 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146d8 esp=0040bebc ebp=0040bf58 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+0xaeec8:
701146d8 3bc7 cmp eax,edi
0:002> p
Time Travel Position: 9ECC1:1676
eax=00000019 ebx=00000035 ecx=00000006 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146da esp=0040bebc ebp=0040bf58 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+0xaeeca:
701146da 0f8d6f020000 jge CoolType!CTCleanup+0xaf13f (7011494f) [br=0]
0:002> p
Time Travel Position: 9ECC1:1677
eax=00000019 ebx=00000035 ecx=00000006 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146e0 esp=0040bebc ebp=0040bf58 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+0xaeed0:
701146e0 8b4dbc mov ecx,dword ptr [ebp-44h] ss:002b:0040bf14=d2e9afe0
0:002> p
Time Travel Position: 9ECC1:1678
eax=00000019 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146e3 esp=0040bebc ebp=0040bf58 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+0xaeed3:
701146e3 03c1 add eax,ecx ; <-------------------------- (14)
0:002> p
Time Travel Position: 9ECC1:1679
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146e5 esp=0040bebc ebp=0040bf58 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+0xaeed5:
701146e5 f745f000200000 test dword ptr [ebp-10h],2000h ss:002b:0040bf48=00002000 ; <-------------------------- (15)
0:002> p
Time Travel Position: 9ECC1:167A
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146ec esp=0040bebc ebp=0040bf58 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+0xaeedc:
701146ec 8945ec mov dword ptr [ebp-14h],eax ss:002b:0040bf44=d2e9aff8
0:002> db eax L7 ; <-------------------------- (16)
d2e9aff9 00 04 80 40 00 c6 00 ...@...
0:002> p
Time Travel Position: 9ECC1:167B
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146ef esp=0040bebc ebp=0040bf58 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+0xaeedf:
701146ef 0f84a7000000 je CoolType!CTCleanup+0xaef8c (7011479c) [br=0]
0:002> p
Time Travel Position: 9ECC1:167C
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146f5 esp=0040bebc ebp=0040bf58 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+0xaeee5:
701146f5 803800 cmp byte ptr [eax],0 ds:002b:d2e9aff9=00 ; <-------------------------- (17)
0:002> p
Time Travel Position: 9ECC1:167D
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146f8 esp=0040bebc ebp=0040bf58 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+0xaeee8:
701146f8 7570 jne CoolType!CTCleanup+0xaef5a (7011476a) [br=0]
0:002> p
Time Travel Position: 9ECC1:167E
eax=d2e9aff9 ebx=00000035 ecx=d2e9afe0 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146fa esp=0040bebc ebp=0040bf58 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+0xaeeea:
701146fa 33c9 xor ecx,ecx
0:002> p
Time Travel Position: 9ECC1:167F
eax=d2e9aff9 ebx=00000035 ecx=00000000 edx=062449b8 esi=d2e9afec edi=00000020
eip=701146fc esp=0040bebc ebp=0040bf58 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+0xaeeec:
701146fc c745cc01000000 mov dword ptr [ebp-34h],1 ss:002b:0040bf24=00000038
0:002> p
Time Travel Position: 9ECC1:1680
eax=d2e9aff9 ebx=00000035 ecx=00000000 edx=062449b8 esi=d2e9afec edi=00000020
eip=70114703 esp=0040bebc ebp=0040bf58 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+0xaeef3:
70114703 40 inc eax ; <-------------------------- (18)
0:002> p
Time Travel Position: 9ECC1:1681
eax=d2e9affa ebx=00000035 ecx=00000000 edx=062449b8 esi=d2e9afec edi=00000020
eip=70114704 esp=0040bebc ebp=0040bf58 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+0xaeef4:
70114704 8945ec mov dword ptr [ebp-14h],eax ss:002b:0040bf44=d2e9aff9
0:002> p
Time Travel Position: 9ECC1:1682
eax=d2e9affa ebx=00000035 ecx=00000000 edx=062449b8 esi=d2e9afec edi=00000020
eip=70114707 esp=0040bebc ebp=0040bf58 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+0xaeef7:
70114707 e9a7000000 jmp CoolType!CTCleanup+0xaefa3 (701147b3)
0:002> db eax L7 ; <-------------------------- (19)
d2e9affa 04 80 40 00 c6 00 ?? ..@...?
0:002> p
Time Travel Position: 9ECC1:1683
eax=d2e9affa ebx=00000035 ecx=00000000 edx=062449b8 esi=d2e9afec edi=00000020
eip=701147b3 esp=0040bebc ebp=0040bf58 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+0xaefa3:
701147b3 8b7dd8 mov edi,dword ptr [ebp-28h] ss:002b:0040bf30=00000019
[...]
Time Travel Position: 9ECC1:168D
eax=00000035 ebx=00000035 ecx=00000000 edx=00000007 esi=d2e9afec edi=00000020
eip=701147d2 esp=0040bebc ebp=0040bf58 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+0xaefc2:
701147d2 85c9 test ecx,ecx
0:002> p
Time Travel Position: 9ECC1:168E
eax=00000035 ebx=00000035 ecx=00000000 edx=00000007 esi=d2e9afec edi=00000020
eip=701147d4 esp=0040bebc ebp=0040bf58 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+0xaefc4:
701147d4 0f45c1 cmovne eax,ecx
0:002> p
Time Travel Position: 9ECC1:168F
eax=00000035 ebx=00000035 ecx=00000000 edx=00000007 esi=d2e9afec edi=00000020
eip=701147d7 esp=0040bebc ebp=0040bf58 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+0xaefc7:
701147d7 8d4d88 lea ecx,[ebp-78h]
0:002> p
Time Travel Position: 9ECC1:1690
eax=00000035 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147da esp=0040bebc ebp=0040bf58 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+0xaefca:
701147da 51 push ecx
0:002> p
Time Travel Position: 9ECC1:1691
eax=00000035 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147db esp=0040beb8 ebp=0040bf58 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+0xaefcb:
701147db 52 push edx ; <-------------------------- (20)
0:002> p
Time Travel Position: 9ECC1:1692
eax=00000035 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147dc esp=0040beb4 ebp=0040bf58 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+0xaefcc:
701147dc 50 push eax
0:002> p
Time Travel Position: 9ECC1:1693
eax=00000035 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147dd esp=0040beb0 ebp=0040bf58 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+0xaefcd:
701147dd 894598 mov dword ptr [ebp-68h],eax ss:002b:0040bef0=00000000
0:002> p
Time Travel Position: 9ECC1:1694
eax=00000035 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147e0 esp=0040beb0 ebp=0040bf58 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+0xaefd0:
701147e0 8d45ec lea eax,[ebp-14h]
0:002> p
Time Travel Position: 9ECC1:1695
eax=0040bf44 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147e3 esp=0040beb0 ebp=0040bf58 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+0xaefd3:
701147e3 57 push edi
0:002> p
Time Travel Position: 9ECC1:1696
eax=0040bf44 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147e4 esp=0040beac ebp=0040bf58 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+0xaefd4:
701147e4 50 push eax
0:002> dd eax L8
0040bf44 d2e9affa 00000000 00000020 00000006
0040bf54 00000007 0040c01c 700b1a53 3f442db4
0:002> p
Time Travel Position: 9ECC1:1697
eax=0040bf44 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147e5 esp=0040bea8 ebp=0040bf58 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+0xaefd5:
701147e5 ff75d4 push dword ptr [ebp-2Ch] ss:002b:0040bf2c=e14570c8
0:002> p
Time Travel Position: 9ECC1:1698
eax=0040bf44 ebx=00000035 ecx=0040bee0 edx=00000007 esi=d2e9afec edi=00000020
eip=701147e8 esp=0040bea4 ebp=0040bf58 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+0xaefd8:
701147e8 e883320000 call CoolType!CTCleanup+0xb2260 (70117a70) ; <-------------------------- (21)
The above code shows the processing of the serialized data of the second tuple variation table
. At (13)
, the register eax
contains the offset value calculated by adding tvs_dataOffset
and tvh_variationDataSize
of the first table. At (14)
, the offset is added to the vulnerable buffer to obtain the serialized data block of the second tuple variation table
. A check is performed at (15)
to determine whether per-tuple-variation-table
contains the private-point-numbers
data. In this case, per-tuple-variation-table
contains private-point-numbers
.
At (16)
, you can observe the content of per-tuple-variation-table
of the second tuple variation table
. At (17)
, the value of ` private_point_number[0] is 0, so the value of
total_ppn_count is 1. The vulnerable buffer is increase by
total_ppn_count at
(18). At
(19), the remaining content of
per-tuple-variation-table` is examined.
Next, a function is called at (21)
to read the remaining fields of per-tuple-variation-table
and the size value of this function comes from the eax
register at (20)
. As noted earlier, the total size of of the second per-tuple-variation-table
(tvh_variationDataSize_2
) is 0x07
, but after subtracting the size of private-point-numbers
from it, the new size value is 6. The incorrect size value is passed to the function without taking into account the already parsed private-point-numbers
. A crash occurs when the function uses this incorrect size to read the remaining fields of the per-tuple-variation-table
. This can be observed at the time of the crash.
0:002> g
(2a04.2208): 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: 9ECC2:0
eax=00000007 ebx=0040bf44 ecx=d2e9b000 edx=00000005 esi=00000005 edi=0040bee0
eip=70117ab8 esp=0040be8c ebp=0040be9c 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+0xb22a8:
70117ab8 0fb601 movzx eax,byte ptr [ecx] ds:002b:d2e9b000=??
0:002> u
CoolType!CTCleanup+0xb22a8:
70117ab8 0fb601 movzx eax,byte ptr [ecx]
70117abb 8945fc mov dword ptr [ebp-4],eax
70117abe 8d4101 lea eax,[ecx+1]
70117ac1 8b4dfc mov ecx,dword ptr [ebp-4]
70117ac4 8bf1 mov esi,ecx
70117ac6 8903 mov dword ptr [ebx],eax
70117ac8 83e63f and esi,3Fh
70117acb 8b07 mov eax,dword ptr [edi]
0:002> kb
# ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0040be9c 701147ed e14570c8 0040bf44 00000020 CoolType!CTCleanup+0xb22a8
01 0040bf58 700b1a53 3f442db4 e144f2c8 e2b04bf8 CoolType!CTCleanup+0xaefdd
02 0040c01c 700afb28 e2b04bf8 3f442db4 e2b04d68 CoolType!CTCleanup+0x4c243
03 0040c10c 700aefa3 3f442c18 3f442d88 3f442d48 CoolType!CTCleanup+0x4a318
04 0040c170 700aedce 3f442c18 3f442d88 3f442d48 CoolType!CTCleanup+0x49793
05 0040c1cc 700a7238 3f442c18 3f442d88 3f442d48 CoolType!CTCleanup+0x495be
06 0040c240 700a7077 0040c390 0040c2c0 00000001 CoolType!CTCleanup+0x41a28
07 0040c25c 700a3097 0040c390 0040c2c0 e769bed0 CoolType!CTCleanup+0x41867
08 0040c3e4 700a2922 e769bed0 70384a18 0040c5d0 CoolType!CTCleanup+0x3d887
09 0040c610 7009b49b 0040d0d0 0040c69c 00000000 CoolType!CTCleanup+0x3d112
0a 0040d11c 7009928a 00000008 00000000 00000000 CoolType!CTCleanup+0x35c8b
0b 0040d1f0 70097d7d a0d1eda8 00000032 0040d2c4 CoolType!CTCleanup+0x33a7a
0c 0040db50 70097418 e73588fc 0040db84 3d2271fc CoolType!CTCleanup+0x3256d
0d 0040deac 7009733c e73588fc e73588e4 3d2271b8 CoolType!CTCleanup+0x31c08
0e 0040dee8 703f03d1 b9f1cf30 e73588fc e73588e4 CoolType!CTCleanup+0x31b2c
0f 0040defc 703e5b3e e73588e4 703e5aa0 8f517570 AGM!AGMTerminate+0xa2f1
10 0040df10 703e0087 8f51757c 70860a50 00000001 AGM!AGMInitialize+0x1c37e
11 0040df34 703ef1c8 0040df60 0040df7c 0040df9c AGM!AGMInitialize+0x168c7
12 0040df48 703ef1f4 00000001 2f9e04fa 00000000 AGM!AGMTerminate+0x90e8
13 0040e004 7417ab2f 08401000 3f800000 00000000 AGM!AGMTerminate+0x9114
14 0040e01c 00000000 00000000 00000000 e734aff0 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-09-03 - Vendor Disclosure
2024-12-10 - Vendor Patch Release
2024-12-11 - Public Release
Discovered by KPC of Cisco Talos.