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.