Anatomy of an Exploit: iOS Race Conditions, Part I

DZone 's Guide to

Anatomy of an Exploit: iOS Race Conditions, Part I

Luca Todesco released source code on ghostbin exploiting a double-free bug in a kernel extension in iOS. Read along as the author goes through the code now to see exactly what he’s up to.

· Mobile Zone ·
Free Resource

A few days ago, Luca Todesco released source code on ghostbin exploiting a double-free bug in a kernel extension in iOS. I’m going through the code now to see exactly what he’s up to, but in essence, the bug is the result of a potential race condition between multiple threads accessing the same resource, from what I can see. And don’t feel bad if you don’t understand what’s going on in this code. I’ve been programming in C for a while and understand operating systems pretty well. This code is a mixture of C and Objective C, and it’s not exactly small at 590 lines.

And also, Mach.

Mach weirdness. So Mach is a micro-kernel that was developed by Carnegie Mellon University in the late 80’s and early 90’s. The last Mach kernel, 3.0, was a true micro-kernel, though the version in XNU is not. It uses tasks instead of processes, and ports for in-kernel IPC (which is just weird). At least it uses threads as threads. Tasks can have zero or more threads, and they communicate with other tasks via messages over ports. This is the only kernel anywhere ever that does this. It worked pretty well for Apple when they migrated over to Intel architectures from PowerPC though and made the migration to ARM for iOS easier too, so I guess there's an upside to all this strangeness.

Onto the exploit. So today, I’m just going to outline the structure of the exploit and describe which functions do what. First, let’s talk about the build chain — I don’t have one that matches his. I’m using clang on a MacBook, and had to tweak his code to get it to compile (specifically, I needed to remove the extern “C” declarations — this is a C++ construct, but the majority of the program seems to be Objective C, or C with Objective C objects, so that's how I built it). I just replaced those with “extern”. I have yet to successfully link the compiled program, though, I’m not sure where some of the undocumented functions are defined (e.g. I'm looking at you, io_service_open_extended(.)).

That said, I’ve read the code, and I have some idea what he’s up to.

Code Structure. So, this exploit is based all around Mach port communication, and much of the code is dedicated to allocating tasks, ports, and IPC message headers. The contents of the messages don't seem that important, really. So the main(.) function loops in an endless while loop sending Mach messages to particular addresses after spawning eight other threads. Seven of those threads do nothing, and I'm not sure why they're created. But who knows, when you're trying to get programs to do things they're not designed to do, sometimes you need to do things that aren't obvious. Perhaps these threads are bogging the processor down making the race condition we're trying to raise easier to trip. After all, these threads call back into the filler(.) function, which implements an interminable spin lock. There's one other thread, that calls the thr(.) function; this is the attacking thread that's trying to trigger an exploit.

thr(.) attempts to trigger the double-free. It sends even more Mach messages and then checks message state. If it finds a corrupted address on one of the Mach messages, we know we've triggered the double-free and corrupted the memory allocator's data structures. It also has fun messages like:

if (mzg->body.msgh_descriptor_count != msg->body.msgh_descriptor_count) {
  NSLog(@"omg0 wtf");

Which, if you look at the conditional, seems like about the right thing to say.

Anyway, shortly after this, you'll find a check for the corrupted header, after which we call pwn_this_b***h(.) and get started exploiting the error condition. I'll go into more detail on this function next time.

apple, exploits, ios

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}