Thursday, August 16, 2018

The Problems and Promise of WebAssembly

Posted by Natalie Silvanovich, Project Zero

WebAssembly is a format that allows code written in assembly-like instructions to be run from JavaScript. It has recently been implemented in all four major browsers. We reviewed each browser’s WebAssembly implementation and found three vulnerabilities. This blog post gives an overview of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 features and attack surface of WebAssembly, as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerabilities we found.

Building WebAssembly


A number of tools can be used to write WebAssembly code. An important goal of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 designers of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 format is to be able to compile C and C++ into WebAssembly, and compilers exist to do so. It is likely that ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r languages will compile into WebAssembly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future. It is also possible to write WebAssembly in WebAssembly text format which is a direct text representation of WebAssembly binary format, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final format of all WebAssembly code.

WebAssembly Modules


Code in WebAssembly binary format starts off in an ArrayBuffer or TypedArray in JavaScript. It is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n loaded into a WebAssembly Module.

var code = new ArrayBuffer(len);
… // write code into ArrayBuffer
var m = new WebAssembly.Module(code);

A module is an object that contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code and initialization information specified by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bytes in binary format. When a module is created, it parses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary, loads needed information into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n translates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly instructions into an intermediate bytecode. Verification of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly instructions is performed during this translation.

WebAssembly binaries consist of a series of sections (binary blobs) with different lengths and types. The sections supported by WebAssembly binary format are as follows.

Section
Code
Description
Type
1
Contains a list of function signatures used by functions defined and called by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module. Each signature has an index, and can be used by multiple functions by specifying that index.
Imports
2
Contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 names and types of objects to be imported. More on this later.
Functions
3
The declarations (including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 index of a signature specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Type Section) of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 functions defined in this module.
Table
4
Contains details about function tables. More on this later.
Memory
5
Contains details about memory. More on this later.
Global
6
Global declarations.
Exports
7
Contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 names and types of objects and functions that will be exported.
Start
8
Specifies a function that will be called on Module start-up.
Elements
9
Table initialization information.
Code
10
The WebAssembly instructions that make up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 body of each function.
Data
11
Memory initialization information.

If a section has a code that is not specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above table, it is called a custom section. Some browsers use custom sections to implement upcoming or experimental features. Unrecognized custom sections are skipped when loading a Module, and can be accessed as TypedArrays in JavaScript.

Module loading starts off by parsing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module. This involves going through each section, verifying its format and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n loading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 needed information into a native structure inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly engine. Most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs that Project Zero found in WebAssembly occured in this phase.

To start, CVE-2018-4222 occurs when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly binary is read out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer containing it. TypedArray objects in JavaScript can contain offsets at which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir underlying ArrayBuffers are accessed. The WebKit implementation of this added cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 offset to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ArrayBuffer data pointer twice. So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code:

var b2 = new ArrayBuffer(1000);
var view = new Int8Array(b2, 700); // offset
var mod = new WebAssembly.Module(view);

Will read memory out-of-bounds in an unfixed version of WebKit. Note that this is also a functional error, as it prevents any TypedArray with an offset from being processed correctly by WebAssembly.

CVE-2018-6092 in Chrome is an example of an issue that occurs when parsing a WebAssembly buffer. Similar issues have been fixed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past. In this vulnerability, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is an integer overflow when parsing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 locals of a function specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code section of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary. The number of locals of each type are added togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size_t that contains this number can wrap on a 32-bit platform.

It is also evident from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section table above (and specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly standard) that sections must be unique and in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct order. For example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function section can’t load unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type section containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 signatures it needs has been loaded already.  
CVE-2018-4121 is an error in section order checking in WebKit. In unfixed versions of WebKit, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 order check gets reset after a custom section is processed, basically allowing sections to occur any number of times in any order. This leads to an overflow in several vectors in WebKit, as its parsing implementation allocates memory based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 assumption that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is only one of each section, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n adds elements to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory without checking. Even without this implementation detail, though, this bug would likely lead to many subtle memory corruption issues in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly engine, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 order and non-duplicate nature of WebAssembly binary sections is very fundamental to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 functionality of WebAssembly.

This vulnerability was independently discovered by Alex Plaskett, Fabian Beterke and Georgi Geshev of MWR Labs, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y describe cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir exploit here.

WebAssembly Instances


After a binary is loaded into a Module, an Instance of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module needs to be created to run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code. An Instance binds cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code to imported objects it needs to run, and does some final initialization.

var code = new ArrayBuffer(len);
… // write code into ArrayBuffer
var m = new WebAssembly.Module(code);
var i = new WebAssembly.Instance(m, imports);

Each module has an Import Section it loaded from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly binary. This section contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 names and types of objects that must be imported from JavaScript for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module to run. There are four types of object that can be imported. Functions (JavaScript or WebAssembly) can be imported and called from WebAssembly. Numeric types can also be imported from JavaScript to populate globals.

Memory and Table objects are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final two types that can be imported. These are new object types added to JavaScript engines for use in WebAssembly. Memory objects contain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly code. This memory can be accessed in JavaScript via an ArrayBuffer, and in WebAssembly via load and store instructions. When creating a Memory object, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly developer specifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial and optional maximum size of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory. The Memory object is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n created with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial memory size allocated, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated memory size can be increased in JavaScript by calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 grow method, and in WebAssembly using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 grow instruction. Memory size can never decrease (at least according to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 standard).

Table objects are function tables for WebAssembly. They contain function objects at specific indexes in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 table, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se functions can be called from WebAssembly using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call_indirect instruction. Like memory, tables have an initial and optional maximum size, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir size can be expanded by calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 grow method in JavaScript. Table objects cannot be expanded in WebAssembly.  Table objects can only contain WebAssembly functions, not JavaScript functions, and an exception is thrown if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wrong type of function is added to a Table object. Currently, WebAssembly only supports one Memory object and one Table object per Instance object. This is likely to change in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future though.

More than one Instance object can share cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same Memory object and Table object. If two or more Instance objects share both of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se objects, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are referred to as being in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same compartment. It is possible to create Instance objects that share a Table object, but not a Memory object, or vice versa, but no compiler should ever create Instances with this property. No compiler ever changes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values in a table after it is initialized, and this is likely to remain true in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future, but it is still possible for JavaScript callers to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m at any time.

There are two ways to add Memory and Table objects to an Instance object. The first is through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Import Section as mentioned above. The second way is to include a Memory or Table Section in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary. Including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se sections causes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly engine to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 needed Memory or Table object for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 module, with parameters provided in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary. It is not valid to specify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se objects in both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Import Section and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table or Memory Section, as this would mean cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is more than one of each object, which is not currently allowed. Memory and Table objects are not mandatory, and it is fairly common for code in WebAssembly not to have a Table object. It is also possible to create WebAssembly code that does not have a Memory object, for example a function that averages cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameters that are passed in, but this is rare in practice.

One feature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se objects that has led to several vulnerabilities is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to increase 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 allocated Memory or Table object. For example, CVE-2018-5093, a series of integer overflow vulnerabilities in increasing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of Memory and Table objects was recently found by OSS-Fuzz. A similar issue was found in Chrome by OSS-Fuzz.

Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r question that immediately comes to mind about Memory objects is 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 internal ArrayBuffer can be detached, as many vulnerabilities have occured in ArrayBuffer detachment. According to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specification, Memory object ArrayBuffers cannot be detached by script, and this is true in all browsers except for Microsoft Edge (Chakra does not allow this, but Edge does). The Memory object ArrayBuffer also do not change size when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Memory object is expanded. Instead, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are detached as soon as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 grow method is called. This prevents any bugs that could occur due to ArrayBuffers changing size.

Out of bounds access is always a concern when allowing script to use memory, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types of issues are fairly uncommon in WebAssembly. One likely reason for this is that a limited number of WebAssembly instructions can access memory, and WebAssembly currently only supports a single page of memory, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code that accesses memory is a WebAssembly engine is actually quite small. Also, on 64-bit systems, WebAssembly implements memory as safe buffers (also called signal buffers). To understand how safe buffers work, it is important to understand how loads and stores work in WebAssembly. These instructions have two operands, an address and an offset. When memory is accessed, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two operands are added to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internal memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Memory object, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting location is where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory access happens. Since both of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se operands are 32-bit integers (note that this is likely to change in future versions of WebAssembly), and required to be above zero, a memory access can be at most 0xfffffffe (4GB) outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated buffer.

Safe buffers work by mapping 4GB into memory space, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n allocating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 portion of memory that is actually needed by WebAssembly code as RW memory at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mapped address space. Memory accesses can be at most 4GB from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory buffer, so all accesses should be in this range. Then, if memory is accessed outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated memory, it will cause a signal (or equivalent OS error), which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly engine, and an appropriate out of bounds exception is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n thrown in JavaScript. Safe buffers eliminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 need for bounds checks in code, making vulnerabilities due to out-of-bounds access less likely on 64-bit systems. Explicit bounds checking is still required on 32-bit systems, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are becoming less common.

After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 imported objects are loaded, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly engine goes through a few more steps to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Instance Object. The Elements Section of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly binary is used to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object, if both of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se exist, 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 Data Section of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebAssembly binary is used to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Memory object, if both exist. Then, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Module is used to create functions, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se functions are exported (attached to a JavaScript object, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are accessible in JavaScript). Finally, if a start function is specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Start Section, it is executed, 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 WebAssembly is ready to run!

var b2 = new ArrayBuffer(1000);
var view = new Int8Array(b2, 700); // offset
var mod = new WebAssembly.Module(a);
var i = new WebAssembly.Instance(m, imports);
i.exports.call_me(); //WebAssembly happens!

The final issue we found involves a number of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se components. It was discovered and fixed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome team before we found it, so it doesn’t have a CVE, but it’s still an interesting bug.

This issue is related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call_indirect instruction which calls a function in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object is called, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function can remove itself from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call. Before this issue was fixed, Chrome relied on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object to prevent it from being freed during garbage collection. So removing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object during a call has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential to cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to use freed memory when it unwinds.

This bug was originally fixed by preventing a Table object from being changed in JavaScript when a WebAssembly call was in progress. Unfortunately, this fix did not completely resolve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue. Since it is possible to create a WebAssembly Instance in any function, it was still possible to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object by creating an Instance that imports cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table object and has an underlying module with an Elements Section. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new Instance is created, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Elements Section is used to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Table, allowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 table to be changed without calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JavaScript function to change a Table object. The issue was ultimately resolved by holding an extra reference to all needed objects for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 duration of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call.

Execution


WebAssembly is executed by calling an exported function. Depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 engine, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intermediate bytecode generated when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Module was parsed is eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r interpreted or used to generate native code via JIT. It’s not uncommon for WebAssembly engines to have bugs where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wrong code is generated for certain sequences of instructions; many such issues have been reported in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs trackers for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 different engines. We didn’t see any such bugs that had a clear security impact though.

The Future


Overall, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs we found in WebAssembly were related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parsing of WebAssembly binaries, and this has been mirrored in vulnerabilities reported by ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r parties. Also, compared to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r recent browser features, surprisingly few vulnerabilities have been reported in it. This is likely due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 simplicity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current design, especially with regards to memory management.

There are two emerging features of WebAssembly that are likely to have a security impact. One is threading. Currently, WebAssembly only supports concurrency via JavaScript workers, but this is likely to change. Since JavaScript is designed assuming that this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only concurrency model, WebAssembly threading has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential to require a lot of code to be thread safe that did not previously need to be, and this could lead to security problems.

WebAssembly GC is anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r potential feature of WebAssembly that could lead to security problems. Currently, some uses of WebAssembly have performance problems due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lack of higher-level memory management in WebAssembly. For example, it is difficult to implement a performant Java Virtual Machine in WebAssembly. If WebAssembly GC is implemented, it will increase cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of applications that WebAssembly can be used for, but it will also make it more likely that vulnerabilities related to memory management will occur in both WebAssembly engines and applications written in WebAssembly.

Tuesday, August 14, 2018

Windows Exploitation Tricks: Exploiting Arbitrary Object Directory Creation for Local Elevation of Privilege

Posted by James Forshaw, Project Zero

And we’re back again for anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r blog in my series on Windows Exploitation tricks. This time I’ll detail how I was able to exploit Issue 1550 which results in an arbitrary object directory being created by using a useful behavior of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CSRSS privileged process. Once again by detailing how I’d exploit a particular vulnerability I hope that readers get a better understanding of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 complexity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows operating system as well as giving Microsoft information on non-memory corruption exploitation techniques so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can mitigate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in some way.

Quick Overview of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vulnerability

Object Manager directories are unrelated to normal file directories. The directories are created and manipulated using a separate set of system calls such as NtCreateDirectoryObject racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than NtCreateFile. Even though cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re not file directories cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re vulnerable to many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same classes of issues as you’d find on a file system including privileged creation and symbolic link planting attacks.

Issue 1550 is a vulnerability that allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 creation of a directory inside a user-controllable location while running as SYSTEM. The root of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 creation of Desktop Bridge applications. The AppInfo service, which is responsible for creating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new application, calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 undocumented API CreateAppContainerToken to do some internal housekeeping. Unfortunately this API creates object directories under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s AppContainerNamedObjects object directory to support redirecting BaseNamedObjects and RPC endpoints by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS.

As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API is called without impersonating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user (it’s normally called in CreateProcess where it typically isn’t as big an issue) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object directories are created with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 identity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service, which is SYSTEM. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user can write arbitrary objects to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir AppContainerNamedObjects directory cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y could drop an object manager symbolic link and redirect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory creation to almost anywhere in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object manager namespace. As a bonus cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory is created with an explicit security descriptor which allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user full access, this will become very important for exploitation.

One difficulty in exploiting this vulnerability is that if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object directory isn’t created under AppContainerNamedObjects because we’ve redirected its location 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 underlying NtCreateLowBoxToken system call which performs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token creation and captures a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory as part of its operation will fail. The directory will be created but almost immediately deleted again. This behavior is actually due to an earlier issue I reported which changes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call’s behavior. This is still exploitable by opening a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 created directory before it’s deleted, and in practice it seems winning this race is reliable as long as your system has multiple processors (which is basically any modern system). With an open handle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory is kept alive as long as needed for exploitation.

This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original PoC I sent to MSRC stopped, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC did was create an arbitrary object directory. You can find this PoC attached to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial bug report in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker. Now let’s get into how we might exploit this vulnerability to go from a normal user account to a privileged SYSTEM account.

Exploitation

The main problem for exploitation is finding a location in which we can create an object directory which can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be leveraged to elevate our privileges. This turns out to be harder than you might think. While almost all Windows applications use object directories under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hood, such as BaseNamedObjects, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 applications typically interact with existing directories which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability can’t be used to modify.

An object directory that would be interesting to abuse is KnownDlls (which I mentioned briefly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous blog in this series). This object directory contains a list of named image section objects, of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form NAME.DLL. When an application calls LoadLibrary on a DLL inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SYSTEM32 directory cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loader first checks if an existing image section is present inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls object directory, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section exists cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n that will be loaded instead of creating a new section object.


KnownDlls is restricted to only being writable by administrators (not strictly true as we’ll see) because if you could drop an arbitrary section object inside this directory you could force a system service to load cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 named DLL, for example using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Diagnostics Hub service I described in my last blog post, and it would map cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section, not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file on disk. However cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability can’t be used to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls object directory ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than adding a new child directory which doesn’t help in exploitation. Maybe we can target KnownDlls indirectly by abusing ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r functionality which our vulnerability can be used with?

Whenever I do research into particular areas of a product I will always note down interesting or unexpected behavior. One example of interesting behavior I discovered when I was researching Windows symbolic links. The Win32 APIs support a function called DefineDosDevice, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purpose of this API is to allow a user to define a new DOS drive letter. The API takes three parameters, a set of flags, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 drive prefix (e.g. X:) to create and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target device to map that drive to. The API’s primary use is in things like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CMD SUBST command.

On modern versions of Windows this API creates an object manager symbolic link inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s own DOS device object directory, a location which can be written to by a normal low privileged user account. However if you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of DefineDosDevice you’ll find that it’s not implemented in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller’s process. Instead cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation calls an RPC method inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current session’s CSRSS service, specifically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method BaseSrvDefineDosDevice inside BASESRV.DLL. The main reason for calling into a privileged service is it allows a user to create a permanent symbolic link which doesn’t get deleted when all handles to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link object are closed. Normally to create a permanent named kernel object you need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SeCreatePermanentPrivilege privilege, however a normal user does not have that privilege. 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 CSRSS does, so by calling into that service we can create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 permanent symbolic link.

The ability to create a permanent symbolic link is certainly interesting, but if we were limited to only creating drive letters in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s DOS devices directory it wouldn’t be especially useful. I also noticed that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation never verified that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lpDeviceName parameter is a drive letter. For example you could specify a name of “GLOBALROOT\RPC Control\ABC” and it would actually create a symbolic link outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s DosDevices directory, specifically in this case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path “\RPC Control\ABC”. This is because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation prepends cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DosDevice prefix “\??” to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device name and passes it to NtCreateSymbolicLink. The kernel would follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full path, finding GLOBALROOT which is a special symbolic link to return to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 root and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path to creating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arbitrary object. It was unclear if this was intentional behavior so I looked in more depth at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation in CSRSS, which is shown in abbreviated form below.

NTSTATUS BaseSrvDefineDosDevice(DWORD dwFlags,
                               LPCWSTR lpDeviceName,
                               LPCWSTR lpTargetPath) {
   WCHAR device_name[];
   snwprintf_s(device_name, L"\\??\\%s", lpDeviceName);
   UNICODE_STRING device_name_ustr;
   OBJECT_ATTRIBUTES objattr;
   RtlInitUnicodeString(&device_name_ustr, device_name);
   InitializeObjectAttributes(&objattr, &device_name_ustr,
                              OBJ_CASE_INSENSITIVE);

   BOOLEAN enable_impersonation = TRUE;
   CsrImpersonateClient();
   HANDLE handle;
   NTSTATUS status = NtOpenSymbolicLinkObject(&handle, DELETE, &objattr);①
   CsrRevertToSelf();

   if (NT_SUCCESS(status)) {
       BOOLEAN is_global = FALSE;

       // Check if we opened a global symbolic link.
       IsGlobalSymbolicLink(handle, &is_global); ②
       if (is_global) {
           enable_impersonation = FALSE; ③
           snwprintf_s(device_name, L"\\GLOBAL??\\%s", lpDeviceName);
           RtlInitUnicodeString(&device_name_ustr, device_name);
       }

       // Delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing symbolic link.
       NtMakeTemporaryObject(handle);
       NtClose(handle);
   }

   if (enable_impersonation) { ④
       CsrRevertToSelf();
   }

   // Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link.
   UNICODE_STRING target_name_ustr;
   RtlInitUnicodeString(&target_name_ustr, lpTargetPath);

   status = NtCreateSymbolicLinkObject(&handle, MAXIMUM_ALLOWED,
                               objattr, target_name_ustr); ⑤

   if (enable_impersonation) { ⑥
       CsrRevertToSelf();
   }
   if (NT_SUCCESS(status)) {
       status = NtMakePermanentObject(handle); ⑦
       NtClose(handle);
   }
   return status;
}

We can see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first thing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code does is build cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device name path cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n try and open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link object for DELETE access . This is because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API supports redefining an existing symbolic link, so it must first try to delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old link. If we follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 default path where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 link doesn’t exist we’ll see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code impersonates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low privileged user in this case) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n creates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link object ⑤, reverts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation ⑥ and makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object permanent ⑦ before returning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 status of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operation. Nothing too surprising, we can understand why we can create arbitrary symbolic links because all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code does is prefix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 passed device name with “\??”. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code impersonates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller when doing any significant operation we can only create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 link in a location that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user could already write to.

What’s more interesting is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 middle conditional, where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target symbolic link is opened for DELETE access, which is needed to call NtMakeTemporaryObject. The opened handle is passed to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r function ②, IsGlobalSymbolicLink, and based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of that function a flag disabling impersonation is set and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device name is recreated again with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global DOS device location \GLOBAL?? as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 prefix ③. What is IsGlobalSymbolicLink doing? Again we can just RE cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function and check.

void IsGlobalSymbolicLink(HANDLE handle, BOOLEAN* is_global) {
   BYTE buffer[0x1000];
   NtQueryObject(handle, ObjectNameInformation, buffer, sizeof(buffer));
   UNICODE_STRING prefix;
   RtlInitUnicodeString(&prefix, L"\\GLOBAL??\\");
   // Check if object name starts with \GLOBAL??
   *is_global = RtlPrefixUnicodeString(&prefix, (PUNICODE_STRING)buffer);
}

The code checks if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 opened object’s name starts with \GLOBAL??\. If so it sets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 is_global flag to TRUE. This results in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flag enabling impersonation being cleared and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device name being rewritten. What this means is that if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller has DELETE access to a symbolic link inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global DOS device directory 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 symbolic link will be recreated without any impersonation, which means it will be created as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SYSTEM user. This in itself doesn’t sound especially interesting as by default only an administrator could open one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global symbolic links for DELETE access. However, what if we could create a child directory underneath cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global DOS device directory which could be written to by a low privileged user? Any symbolic link in that directory could be opened for DELETE access as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low privileged user could specify any access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y liked, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code would flag cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 link as being global, when in fact that’s not really cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case, disable impersonation and recreate it as SYSTEM. And guess what, we have a vulnerability which would allow us to create an arbitrary object directory under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global DOS device directory.

Again this might not be very exploitable if it wasn’t for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rewriting of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path. We can abuse 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 path “\??\ABC” isn’t cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as “\GLOBAL??\ABC” to construct a mechanism to create an arbitrary symbolic link anywhere in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object manager namespace as SYSTEM. How does this help us? If you write a symbolic link to KnownDlls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it will be followed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel when opening a section requested by DLL loader. Therefore even though we can’t directly create a new section object inside KnownDlls, we can create a symbolic link which points outside that directory to a place that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low-privileged user can create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section object. We can now abuse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hijack to load an arbitrary DLL into memory inside a privileged process and privilege elevation is achieved.

Pulling this all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r we can exploit our vulnerability using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following steps:

  1. Use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory “\GLOBAL??\KnownDlls”
  2. Create a symbolic link inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new directory with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DLL to hijack, such as TAPI32.DLL. The target of this link doesn’t matter.
  3. Inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s DOS device directory create a new symbolic link called “GLOBALROOT” pointing to “\GLOBAL??”. This will override cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 real GLOBALROOT symbolic link object when a caller accesses it via cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s DOS device directory.
  4. Call DefineDosDevice specifying a device name of “GLOBALROOT\KnownDlls\TAPI32.DLL” and a target path of a location that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user can create section objects inside. This will result in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following operations:
    1. CSRSS opens cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link “\??\GLOBALROOT\KnownDlls\TAPI32.DLL” which results in opening “\GLOBAL??\KnownDlls\TAPI32.DLL”. As this is controlled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 open succeeds, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 link is considered global which disables impersonation.
    2. CSRSS rewrites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path to “\GLOBAL??\GLOBALROOT\KnownDlls\TAPI32.DLL” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls NtCreateSymbolicLinkObject without impersonation. This results in following cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 real GLOBALROOT link, which results in creating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link “\KnownDlls\TAPI32.DLL” with an arbitrary target path.
  5. Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 image section object at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target location for an arbitrary DLL, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n force it to be loaded into a privileged service such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Diagnostics Hub by getting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service to call LoadLibrary with a path to TAPI32.DLL.
  6. Privilege escalation is achieved.

Abusing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DefineDosDevice API actually has a second use, it’s an Administrator to Protected Process Light (PPL) bypass. PPL processes still use KnownDlls, so if you can add a new entry you can inject code into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 protected process. To prevent that attack vector Windows marks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls directory with a Process Trust Label which blocks all but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 highest level level PPL process from writing to it, as shown below.


How does our exploit work cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n? CSRSS actually runs as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 highest level PPL so is allowed to write to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls directory. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation is dropped cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 identity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process is used which will allow full access.

If you want to test this exploit I’ve attached cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new PoC to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker here.

Wrapping Up

You might wonder at this point if I reported cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behavior of DefineDosDevice to MSRC? I didn’t, mainly because it’s not in itself a vulnerability. Even in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of Administrator to PPL, MSRC do not consider that a serviceable security boundary (example). Of course cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows developers might choose to try and change this behavior in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future, assuming it doesn’t cause a major regression in compatibility. This function has been around since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 early days of Windows and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current behavior since at least Windows XP so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s probably something which relies on it. By describing this exploit in detail, I want to give MS as much information as necessary to address cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation technique in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future.

I did report cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability to MSRC and it was fixed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 June 2018 patches. How did Microsoft fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability? The developers added a new API, CreateAppContainerTokenForUser which impersonates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token during creation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new AppContainer token. By impersonating during token creation cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code ensures that all objects are created only with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privileges of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user. As it’s a new API existing code would have to be changed to use it, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a chance you could still find code which uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old CreateAppContainerToken in a vulnerable pattern.

Exploiting vulnerabilities on any platform sometimes requires pretty in-depth knowledge about how different components interact. In this case while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial vulnerability was clearly a security issue, it’s not clear how you could proceed to full exploitation. It’s always worth keeping a log of interesting behavior which you encounter during reverse engineering as even if something is not a security bug itself, it might be useful to exploit anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r vulnerability.