Monday, March 28, 2016

Life After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap

Posted by Natalie Silvanovich, Mourner of Lost Exploits

Over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past few months, Adobe has introduced a number of changes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash Player heap with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 goal of reducing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitability of certain types of vulnerabilities in Flash, especially use-after-frees. I wrote an exploit involving two bugs discovered after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap was implemented to explore how it impacts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir exploitability.

The Isolated Heap


The Flash heap, MMgc, is a garbage collected heap that also supports unmanaged fixed allocations. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re have been many exploits in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild that used certain properties of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap to aid exploitation. In particular, many exploits used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation properties of Vectors to gain read/write access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire Flash memory space via heap memory corruption bugs. Exploits that use ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r object types, such as ByteArray and BitmapData have also been seen in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild.

MMgc was originally implemented as a type and size bucketed allocator. When memory is requested, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocator that is called depends on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of memory that is needed. This is related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 garbage collection properties of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory. If it is not garbage collected, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Fixed allocator is used, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Garbage-Collected (GC) allocator is used. Within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GC allocator, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are about eight subtypes of memory that can be allocated, related to 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 memory contains pointers and whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r those pointers have custom finalizers or GC routines that need to be called. Within each type, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 request is sorted by size, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory is allocated on a heap page for that size. Large requests are allocated on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own page.

The Isolated Heap introduces partitioning to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap, essentially a third factor which determines where memory is allocated. There is separate memory for each partition, which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n split into subsections for different types and sizes. The goal of partitioning is to allocate objects that are likely to contain memory corruption bugs in a different area of memory than objects that are likely to be useful in exploiting memory corruption bugs, and generally add more entropy to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap.

There are currently three partitions on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap. The first partition is generally used for objects that contain pointers: script objects, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir backing GC-memory and certain pointer arrays. The second partition is used for objects that contain non-pointer data, mostly arrays of primitive types. The third partition is used for a small number of objects that have a history of being used in exploits. These are typically variable-sized data buffer objects. Outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap, checksumming has also been implemented to detect and abort if certain sensitive objects are ever altered.

CVE-2016-0998


CVE-2016-0998 was discovered by Mateusz Jurczyk and I while fuzzing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash Player (full code for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit can be found attached to this bug). It was reported to Adobe on February 3, 2016 and fixed by Adobe on March 10, 2016. It is a good example of a bug that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap makes more difficult to exploit.

The bug is an uninitialized variable in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fix to an ActionScript 2 use-after-free bug. Roughly 80 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types of issues have been fixed by Adobe in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past year, and two uninitialized variable issues were introduced in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fixes.

This issue is fairly easy to reproduce, a proof-of-concept for this issue in its entirety is:

var o = {};
o.unwatch();

The bug occurs because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free check in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unwatch method attempts to convert its first parameter to a string by calling toString on it before continuing with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method where toString  could cause problems by freeing an object. However, Flash does not check that this parameter exists before calling toString on it. In pseudo-code, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rough behaviour of this method is:

void* args = alloca( args_size );
for( int i = 0; i < args_size; i++){
// Init args
}

if ( ((int) args[0]) & 6 == 6 )
args[0] = call_toString( args[0] );

if ( args_size < 1)
exit();

There’s a few interesting things to note about this bug. First, on Flash, alloca(0) allocates 16 bytes (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 minimum allowed size), but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initialization loop doesn’t run, so this memory contains whatever was 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 last time this memory was used, which is not part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current call. Second, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable behaviour only occurs if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack ends in 6. The purpose of this behaviour is to ensure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameter is a ScriptObject -- Flash arguments can be many types, such a strings, integers, objects, etc., and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last three bits of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value indicates its type, with 6 indicating a ScriptObject. Finally, this bug bails pretty quickly if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 argument array is too small. There’s only one function, call_toString that’s called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uninitialized value. This function searches through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ScriptObject’s variables for a method called toString, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls it, calling some virtual methods in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process.

With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above constraints, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few ways to exploit this bug:

  1. Put an absolute pointer value on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack. The benefit of this is that you can guarantee that it ends in 6. The downside is that you need a separate bug to bypass ASLR, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no way to get your bearings ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise
  2. Put a pointer to some type of object or buffer that is not a ScriptObject on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, and use type confusion for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit. This is somewhat challenging for this particular bug, because valid pointers that end in 6 are unusual on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, as most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are aligned.  The only situation where unaligned pointers are typically on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack is when manipulating data buffers such as strings where each byte is accessed individually.
  3. Make this bug into a use-after-free. Put a stale pointer to a ScriptObject on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack and wait for it to be freed and reallocated, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use type confusion for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit

Option 2 seemed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most practical up front, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap posed some challenges. As noted above, if a call puts an unaligned pointer on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, it is probably manipulating some sort of byte data that does not contain pointers, as pointer access needs to be aligned. So it is probably possible to make args[0] point to a buffer type, such as a ByteArray in ActionScript, but ASLR is still a problem, because call_toString calls virtual functions on args[0] , and without knowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of any code addresses, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer that will be treated as a vtable can’t be set to a reasonable value. One possible way of solving this problem would be to have args[0] point to a buffer, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n realloc it to be something else that has a valid vtable, but all script-controllable byte buffers are allocated in partition 3, which is not used for any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data types that contain pointers, so this isn’t possible with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap.

I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n tried Option 3, and tried to reallocate a different object in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 place of a ScriptObject. This bug more amenable to this than a lot of ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r bugs, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no limitation to when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object needs to be reallocated, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than it needs to be reallocated after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to it is outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 valid stack (i.e. cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pointer is higher than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value), and it needs to remain allocated until it is used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug. These constraints aren’t very limiting, as basically any object in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash Player can be allocated in this window. That said, only allocations with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same partition, type and size as a ScriptObject will be allocated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed memory. Looking at object allocations in Flash, only about 10 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r objects have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se properties, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y all extend cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same class, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AS3 ScriptObject class (which is different from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AS2 ScriptObject that is freed). Unfortunately though, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first virtual function that this bug calls on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reallocated buffer maps to ScriptObject::getDescendants, which immediately throws an ActionScript 3 exception, which leads to a null pointer crash, because exception handlers haven’t been properly initialized. So in this case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re isn’t an appropriate object that can be allocated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 place of an AS3 ScriptObject that can make this bug exploitable as a use-after-free.

At this point, I didn’t think it was very likely that this bug would be exploitable without a second information leak vulnerability, so I tried exploiting it with a second bug.

CVE-2016-0984


CVE-2016-0984 is a use-after-free in sound processing in which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed buffer can only be read. I reported CVE-2016-0984 on January 11, 2016 and Adobe released a patch on February 16, 2016.

A proof-of-concept for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug is as follows:

var s = new Sound();
var b = new ByteArray();
for( var i = 0; i < 1600; i++){
b.writeByte(1);
}
b.position = 0;
s.loadPCMFromByteArray(b, 100, "float", false, 2.0);
var c = new ByteArray();
for(var i = 0; i < 2; i++){
c.writeByte(1);
}
c.position = 0;
try{
s.loadPCMFromByteArray(c, 1, "float", false, 2.0);
}catch(e:Error){
trace(e.message);
}

var d = new ByteArray();
s.extract(d, 1, 0);

This bug is related to exception handling in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loadPCMFromByteArray method. This method loads sound data from an array that is provided by ActionScript, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n processes it, and stores it internally in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Sound object. The general flow of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function is as follows:

if ( input_size < needed_size ){ // needed_size is wrong
throwASException();
}

delete[] m_pcm;
char* sound_data = new char[input_size];

for( int i = 0; i < input_size; i++){
sound_data = inputArray.readStuff(); // can throw exception
}

m_pcm = sound_data;

The code attempts to check that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right size and throws an exception before it does any pointer manipulation, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is an arithmetic error in how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size is calculated, so some situations in which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array is too small will get through (see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tracker for exact details on how to trigger this condition). In this case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input array will throw an exception when it is read, which means that m_pcm will be freed but not reallocated. This is a fairly versatile bug, in that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array that is freed can be of any size, though it is always a character array in partition 2, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data heap.

The first step was to use this bug to obtain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of a vtable to break ASLR. It wasn’t immediately obvious how to do this, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap partition cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array is allocated if generally used for primitive arrays. There were two exceptions to this I was aware of. First, arrays of pointer that aren’t void pointers are allocated on this heap, but this isn’t particularly helpful for this bug, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y tend to be pointers to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r primitive data types, and even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were pointers to objects, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no way to use this bug to iterate through pointers, it can only be used to read values off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap without knowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir location. Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r property I noticed is that object arrays are also allocated in this partition, so if an array of objects that call virtual methods (or contain function pointers) is allocated, you could read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code pointers off of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap. When I looked though, I couldn’t find a single array of virtual objects allocated in a way that is script-controllable in Flash, as arrays of pointers are usually used instead.

Eventually, I discovered that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ActionScript JIT LIR implements its own basic heap, and allocates new pages as large char arrays, which are allocated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same heap partition as ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r char arrays. These pages have variable sizes, and often contain objects with vtables. By selecting a PCM array allocation size that lines up with a frequent LIR allocation, I was able to read a vtable off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap.

The next step was to get a pointer to a buffer I could control in script. It is possible to also use CVE-2016-0998 for this, but I suspected that using this bug could do it more simply and reliably. Since arrays of char pointers are allocated on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same heap partition as sound PCM data, char pointers could be easily read. I used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AS3 function LocaleID.determinePreferredLocales to allocate a char* array based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 String vector that is provided as input. Unfortunately though, ActionScript strings aren’t ideal for exploits. They are immutable after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are allocated, and worse, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y terminate as soon as a NULL character is reached, which means on 64-bit systems, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can only ever contain one pointer. The best solution to this would be to allocate an array of pointers to something more controllable, such as a byte or int Array, but unfortunately in ActionScript, arrays of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types of pointers are fairly unusual, and when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y exist, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir size is usually not controllable from script. So instead, I reallocated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string data that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 char pointers pointed to, so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were integer arrays instead. This was possible in part because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 strings allocated internal to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LocaleID.determinePreferedLocales method are not true Flash strings that are accessible via script, but character arrays, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y show up in partition 2 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data partition) as opposed to partition 3 (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitable objects partition).

I used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData.paletteMap method to allocate integer arrays in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 place of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 character arrays allocated by LocaleID.determinePreferedLocales. This method accepts input of four integer arrays of size 256, and copies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to a larger int array of length 1024. These arrays are not mutable, but since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer, and 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 buffer have been determined at this point, it doesn’t matter, as all values that need to be in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array can be calculated before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array is created. Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r undesirable property of this method is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arrays are freed at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a trick for getting around it. If any element of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arrays provided to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method is not an integer, Flash will attempt to call valueOf on it to convert it to a number. So if a late element (for example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last element of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fourth array) has a valueOf that throws an exception, execution of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method will stop. In this case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 large int array will be allocated, and most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input will be copied to it, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function that processes and frees cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arrays will be skipped. This is a useful trick to avoid objects being freed that works in a lot of methods.

At this point, we have a pointer to a vtable, and a pointer to a buffer we control, so it’s fairly straightforward to gain code execution using CVE-2016-0998

Putting it all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r


For CVE-2016-0998 to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated buffer, a pointer to it with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final three bits set to 6 needs to be put on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack. There are a few ways to do this, one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m being UTF conversion. UTF-8 to UTF-16 conversion is done on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of resulting UTF-16 string is less than 256 bytes, which leads to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 character values of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string being written to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack.

To start off, my exploit grows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack. This is just to avoid any values that have already been written from causing problems. This isn’t as straightforward as one would expect. The ActionScript stack is not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C++ stack (where this bug occurs), so calling a function recursively in ActionScript won’t grow it. Instead, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re needs to be a loop in C++. To cause this, I triggered a situation where toString would be called recursively, which would be done in C++. In ActionScript:

_global.v = 31;
_global.mc = this;
var o = {toString : f};
this.swapDepths(o);

function f(){
if(_global.v > 0){
_global.v = _global.v - 1;
_global.mc.swapDepths(this);
}else{

var t = _global.mc;
t.swapDepths(d, 2);
}
return 
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
}

This code calls swapDepths, which calls toString from C++, which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n recursively calls swapDepths again, growing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack.

The value that is returned from this type of function cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n gets converted from UTF-8 to UTF-16, so its contents get put on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack. This can be used to put 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 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 controllable buffer on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack. Unfortunately, conversion only happens if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 String is encoded statically in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SWF, a string generated during AS execution won’t work. So a SWF needs to dynamically be created as a part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit.

This process can be seen in test.cgi. The first part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, soundPCM.swf uses CVE-2016-0984 to break ASLR and create a buffer, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it passes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer to test.cgi via URL parameters in JavaScript. This calls into Python, and adds cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct address into a static string in a SWF called new.swf. Note that a UTF-8 converter is implemented in Python, this is because standard UTF encoding leads to characters of different lengths, and putting different lengths of strings into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SWF causes “movement” in memory when it is loaded, which can cause problems with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit which relies on static offsets. The implemented converter always creates three-byte UTF-8 encodings even if a shorter one is possible based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specific buffer pointer value. Also note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full string in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SWF will not get fully converted, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 0x0000 value at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 64-bit pointer will be treated as a null, and processing will stop. This isn’t ideal, it means that only one pointer can ever be copied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, but it is a constraint that can be worked around.

At this point, we have a SWF that puts a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, we now just need to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit. I encoded this into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same SWF for simplicity. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SWF has been created, it is loaded once with URL parameter num=15, which sets up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n with URL parameter num=14, which triggers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, causing native toString to be called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer that’s provided.

What’s in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer

The last step is to figure out what to put in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer. Running through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 native call, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a few pointers that need to be set to something valid to avoid crashes (I pointed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m back to various locations in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same buffer), and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n a virtual call is made to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer. Setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 head of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call sees as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable to a location later in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer, and creating a fake vtable in that memory, it’s possible to make a call into a gadget. This exploit uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following one:

mov rdi, rax
call [rax + 0x28]

This sets rdi to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 head of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable, which is set to a string command, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n rax + 0x28 (0x28 bytes into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable) is set a location which calls system in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash plug-in, which triggers a call to system.

Conclusion


The Isolated Heap made exploiting CVE-2016-0998 more difficult and time consuming, and also made exploitation require a separate information leak bug, which probably would not have been required before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap changes. There are a couple weaknesses in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated heap, especially cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data partition for JIT allocation, and allocating pointer arrays on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data heap. We are working with Adobe to implement improvements to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap in future versions of Flash. It is challenging to harden a heap against exploitation, especially in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 face of high-quality bugs, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Isolated Heap is a substantial improvement.

Tuesday, March 22, 2016

Race you to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel!

Posted by Ian Beer of Google Project Zero

The OS X and iOS kernel code responsible for loading a setuid root binary invalidates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port after first swapping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new virtual memory map pointer into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task object, leaving a short race window where you can manipulate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory of an euid 0 process before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port is invalidated. Going a step furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r this also allows you to also gain any entitlement and, on OS X, load an unsigned kernel extension.


I reported this bug to Apple on December 16th 2015 and it was patched in OS X 10.11.4/iOS 9.3 as CVE-2016-1757. For more technical details see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original bug report where you can also grab cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 updated exploit.

Task Ports

If you’ve ever tried to use ptrace on OS X you were probably sorely disappointed. Whilst cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 syscall does exists it’s severely limited in what it can do. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no support for peeking and poking memory, a pretty fundamental use-case.


This is one of many areas of XNU where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 duality of its kernel is evident; along with ptrace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a parallel abstraction layer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mach side of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel which supports building debugging tools via a set of special mach task ports


Each process executing on OS X has a task port. For example, to allocate a page of memory in your process you might use code like this:


mach_vm_address_t addr = 0;
mach_vm_allocate(mach_task_self(),
                &addr,
                0x1000,
                VM_FLAGS_ANYWHERE);


mach_vm_allocate is a MIG method implemented by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel (and defined in mach_vm.defs in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 xnu kernel source.) The first argument to this method is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current task port; if you happened to have send rights to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r task’s task port and you were to call this method passing that ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r task’s task port 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 allocation would end up in that ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r task’s virtual address space, even though your task made cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call. Similarly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach_vm_read and mach_vm_write methods allow you to read and write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory of ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes if you  have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir task ports, effectively giving you complete control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.


By default tasks only have send rights to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own task ports, but it’s easy to give ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes send rights to your task port using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 standard mach messaging mechanisms.

execve

Usually new task ports will only be created when new processes are created (via fork or posix_spawn). Just execing a new binary won’t reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task port. This leads to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 obvious question: since having a send right to a process’s task port give you complete control over that process, how do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y deal with SUID binaries where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exec call will increase 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 process?


Looking through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exec code we find this snippet:


/*
* Have mach reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task and thread ports.
* We don't want anyone who had cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ports before
* a setuid exec to be able to access/control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365
* task/thread after.
*/
ipc_task_reset(p->task);


Sounds sensible. But execve is a really complex syscall and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a lot going on here:



This diagram outline cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 four major phases of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exec syscall which we’re interested in along with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lifetimes of some data structures.


In phase 1 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port is still valid, and via cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task struct gives us access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old vm_map which still contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual address space of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task prior to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exec. As part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 load_machfile method cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel will create a new vm_map into which it will load cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new executable image. Note though that at this point cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map isn’t matched up with any task; it’s just a virtual address space with no process.


In phase 2 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parse_machfile method does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual parse and load of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MachO image into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new virtual address space. It’s also during this phase that any code signatures which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary has are checked; we’ll come back to that detail later.


In phase 3 load_machfile calls swap_task_map; this sets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task struct to point to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map into which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target executable was just loaded. From this point on any mach_vm* methods invoked on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port will target cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map.


In phase 4 exec_handle_sugid will check if this binary is SUID, and if it is, will reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task port, at which point cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port will no longer work.

Somethings not right cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re…

From this high-level view it’s clear that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a fundamental race condition. Between phase 3, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vm_map is swapped, and phase 4, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task port is invalidated, we will have full read/write access via cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old task port to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loaded binary which is about to be executed, even if it’s SUID which means that we can just use mach_vm_write to overwrite its text segment with code we control!


From cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 diagram it’s hard to tell but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s actually quite a long period between those two phases, certainly enough time to sneak in a few mach kernel MIG calls.

Building a reliable exploit

There’s one small stumbling block to overcome though: although we can now try to write to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map, where should we write? Userspace ASLR on OS X (for binaries, not dynamic libraries) is randomized per-exec so we first have to figure out where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel loaded cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 image.


Luckily with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task port we can do a lot more than just blindly read and write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map; we can also API’s like mach_vm_region to ask about properties of memory regions in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 map. In this case we just loop constantly asking for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lowest mapping. When it changes we know that it changed to 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 image in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map and  that we’re now in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 race window between phases 3 and 4.


Using this base address we can work out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary’s entrypoint in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new vm_map, mark that page as RWX using mach_vm_protect and overwrite it with shellcode using mach_vm_write.


Run root_shell.sh in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attached exploit to see this in action. It should work out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 box on any semi-recent OS X system, using otool to extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entrypoint of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 traceroute6 suid-root executable.

Going furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r: codesigning and entitlements

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exec phases diagram I mentioned that parse_machfile (in phase 2) is responsible for both loading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MachO as well as verifying any code signatures present. You might ask why this is relevant on OS X since, unlike iOS, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no mandatory userspace code signing and we can quite happily execute unsigned code anyway.


But OS X does use userspace code signing to enforce entitlements which are just xml blobs stored in your MachO and signed as part of your code signature.


Kernel code can check whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user space processes have particular entitlements (via IOTaskHasEntitlement) and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel kext loading code will now only accept load requests from processes which are both running as root and also have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 com.apple.rootless.kext-management entitlement.


This is particularly important since on OS X kext code signatures are enforced by userspace. This means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kext-management entitlement is a vital part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 separation between root in userspace and kernel code execution.


Two system binaries which do have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kext-management entitlement are kextd and kextload; so in order to defeat kernel code signing we just need to first exec a suid-root binary to get root cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n exec eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r kextload or kextd to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right entitlement.

Patching kextload

kextload is probably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 easier target for a binary patch since it’s a standalone tool which can load a kext without talking to to kextd. We just need to patch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 checkAccess function so that kextload thinks it can’t reach kextd and will try to load cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kext itself. Then patch out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calls to checkKextSignature and checkSignaturesOfDependents such that kextload thinks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y succeeded and it will now load any kext, signed or unsigned :-)

The released exploit contain a binary patch file to remove cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 signature checks in kextload on OS X 10.11.3 as well as a simple HelloWorld kext and load_kext.sh and unload_kext.sh scripts to load and unload it. These can be run as a regular user. Look in Console.app to see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel debug printf output.