Attacking the XNU Kernel For Fun And Profit – Part 2

This blog post is part of a series of posts in which I will discuss several techniques to own XNU, the kernel used by Apple’s OS X and iOS. My focus will be on heap-based attacks, such as heap overflows, double frees, use-after-frees and zone confusion.

In the previous blog post, I outlined some very important details on how the kernel heap works on both iOS and OS X. In this one, I’ll outline several kernel hardening features Apple has added over the years to stop kernel exploitation. A basic knowledge of the impact of these measures is required in other to further perform any additional exploit. I will begin the tale of the exploitation of a real-world exploit, CVE-2015-1140, a textbook heap overflow present up to Mac OS X 10.10.2 (included) which allowed escalation to Ring 0 from an unprivileged user. I will be describing the techniques involved in this exploit. In the next blog post, I will be showing code to pull these techniques off with CVE-2015-1140.

1) iOS Only – Kernel/User Address Space Isolation
Can be enabled on OS X with no_shared_cr3, but impacts performance.
Impact: Kernel will not be able to read userland data without special routines being used. In the future, SMAP will provide the same protection with no performance impact(?).

2) x86_64 Only – SMEP
Impact: You won’t be able to execute from userland address space when in Ring 0. This still allows read and write to the userland address space. If no_shared_cr3 is used, SMEP becomes useless since kernel/user address space isolation already prevents userland address space access (incl. execution).

3) Kernel W^X
Impact: Executable pages are not writeable. Writeable pages are not executable. This is quite an hassle when combined with SMEP or AS Isolation, because without these instead of jumping to kernel address space you can jump to userland address space mapped as r-x and ring0 will happily run it.

4) KASLR – Kernel Address Space Layout Randomisation
Impact: The obvious way to go around 1, 2 and 3 is to do data-reuse or code-reuse attacks, such as ROP. But you need to be able to locate the data you want to use in memory, by sliding everything randomly on each boot this becomes theoretically impossible.

5) Allocator Hardening / Safe Unlinking
Impact: Prevents the allocator from being exploited. This stops generic heap attacks from working.

Note: There are other “hardening” features all around the kernel, but I’ll be focusing on these since these are the ones that will pretty much always get into your way when writing a kernel exploit.

The Vulnerability

After a couple of days looking around the source code of the open-source kernel extensions installed by default on Mac OS X, I spotted a strange file inside IOHIDFamily, IOHIDSecurePromptClient.cpp.
It became obvious that whoever coded that was high on drugs at the time, since out of 13 functions it exposes to any unprivileged user, one is a “null terminator”, which shouldn’t be an exposed method but it is, due to an off-by-one bug, three are methods that do an unrestricted write-what-where (but the where is limited to a 32 bits wide pointer), and as of 10.10.1 were so broken that they could not possibly be used without crashing the kernel, one is an heap overflow, and generally speaking I do not get the point of this IOUserClient. I am not sure what it is usually used for, but I guess it’s used for nothing at all since half of it’s functions are broken. This class was removed in it’s entirety on 10.10.3, and two methods were removed in 10.10.2.

The heap overflow is fairly simple; the 12th selector (10th after 10.10.2) will take some data from userland and copy it into a fixed-size buffer. There is some form of “sanity checking”, but it’s ridiculously stupid since the cap on the user-passed data’s length is 4095, and the buffer is 256 bytes in size.

We also note that the 256-byte buffer we’ll overflow from is allocated once you request the creation of a new IOHIDSecurePromptClient, so we can perform the allocation from userland at will.

We can fully control the data of any 256 byte allocation adjacent to our buffer, as long as our buffer isn’t the last allocation in a page because our overflow would be writing in an unmapped area. Since a page is 4096 bytes, 16 256-byte allocations fit in a page, and the chance of being the last allocation is 1/16th. This means the exploit will fail around 1/16th if we cannot guess the heap address of our buffer.

Controlling the Heap

In my previous blog post I described some details on how the kernel heap allocator works. In this blog post I’ll make use of “adjacent objects”. Remember, there are different “heaps”, each with a fixed allocation size. When you request an allocation, the last-free’d memory chunks in your size’s “heap” is returned. When no more free memory is available, a new page is mapped and divided in new free memory chunks. So, to allocate adjacent objects what you have to do is fill the interested heap, so a new page is taken. Once a new page is used for allocations, since you know in what order the free memory chunks are used, you can easily allocate adjacent objects. This technique is described with great detail in many papers, and is commonly called “Heap Feng Shui”.

Gaining Code Execution

Due to allocator hardening, trying to perform a generic attack is a waste of time, and since there is no metadata in allocated chunks (just in free ones), after writing the 256th byte we will be directly controlling the values of an allocated chunk. Since the XNU kernel makes use of C++ and the creation/destruction of C++ objects can be controlled from userland, overwriting the vtable pointer of such a C++ object gives us control over the instruction pointer. But what do we use as vtable pointer? An userland pointer would be okay on OS X, but it is not okay today on iOS and won’t be okay anymore sometime in the future on OS X due to Kernel/User Address Space Isolation coming to x86_64 as SMAP. Another important question is: what will we execute? Userland address space can not be executed due to SMEP and we don’t know the kernel address space layout due to KASLR, so we’re at a dead end. We need to work some more.

Breaking KASLR

On XNU, Kernel Address Space Layout Randomisation is pretty simple. A byte is generated randomly at boot. From there, a “kernel slide” is derived. This kernel slide is then added to the base address of kernel extensions as well as the kernel itself. The kernel slide is the same for every kernel address, so leaking a pointer to kernel or kernel extension text or data will always break KASLR, since you can calculate the pointer from userland and subtract the leaked value from the calculated value to find out the value of the slide. Once the slide is known, you are free to use data/code-reuse attacks.

[…]

Backtrace (CPU 0), xxx : Return Address
xxx : 0xffffff800792bda1
xxx : 0xffffff8007e5c436
[…]

Kernel slide: 0x0000000007600000
Kernel text base: 0xffffff8007800000

[…]

— Kernel Panic on KASLR-enabled Mac OS X Machine

Controlling Data In Kernel Address Space

To do this is by finding some kernel function that allows user-land to pass data to be stored in a kernel buffer, and then leak this buffer’s address.
A way to do this is by using pipe() and write(). The data you will write() is copied into a kalloc’d buffer with no metadata. Metadata about your pipe (such as data length) is stored in a fixed-size allocation and is not stored with your data. This is useful if you need to control every byte of a kalloc allocation.

Another way is by sending OOL data via a mach message. This OOL data will be copied into the kernel AS via vm_map_copyin, which will allocate enough bytes to hold your data + 0x58 (on recent x86_64 XNU). Metadata is stored inline. When vm_map_copyout is used, this data is copied back into userland address space.
This is useful since metadata holds your data’s length, and corruption of the length will make vm_map_copyout read out-of-bounds. Furthermore, a pointer called “kdata” will point to the data that will be copied, thus controlling this pointer allows you to read anywhere in kernel memory, useful to find gadgets without having to access the file system to read the kernel. Placing two of these vm_map_copy structs next to another, then corrupting the first one’s size to read the second one’s header allows you to leak the kdata pointer, which will be pointing to the user-controlled data stored in kernel heap. You can then use this pointer to do anything you wish, and it’ll point to your user-controlled data!

struct vm_map_copy {
	int			type;
#define VM_MAP_COPY_KERNEL_BUFFER	3
	vm_object_offset_t	offset;
	vm_map_size_t		size;
	union { 
            [...]
	    struct {				
		void			*kdata;
		vm_size_t		kalloc_size;
	    } c_k; /* KERNEL_BUFFER */
	} c_u;
};
#define cpy_kdata		c_u.c_k.kdata
#define cpy_kalloc_size		c_u.c_k.kalloc_size
kern_return_t
vm_map_copyout(
	vm_map_t		dst_map,
	vm_map_address_t	*dst_addr,	/* OUT */
	vm_map_copy_t		copy)
{
        if (copy->type == VM_MAP_COPY_KERNEL_BUFFER)
                return vm_map_copyout_kernel_buffer(dst_map, dst_addr, copy, FALSE, consume_on_success);
static kern_return_t
vm_map_copyout_kernel_buffer(
	vm_map_t		map,
	vm_map_address_t	*addr,	/* IN/OUT */
	vm_map_copy_t		copy,
	boolean_t		overwrite,
	boolean_t		consume_on_success)
{
        [...]
        copyout(copy->cpy_kdata, *addr, (vm_size_t) copy->size);
        [...]
        kfree(copy, copy->cpy_kalloc_size);
        [...]
}

 

Breaking KASLR – Again

You’ll have to pay attention to some details.
From the previous part of “Breaking KASLR”:

The kernel slide is the same for every kernel address, so leaking a pointer to kernel or kernel extension text or data will always break KASLR, since you can calculate the pointer from userland and subtract the leaked value from the calculated value to find out the value of the slide.

Now, from “Gaining Code Execution”:

Since the XNU kernel makes use of C++ and the creation/destruction of C++ objects can be controlled from userland, overwriting the vtable pointer of such a C++ object gives us control over the instruction pointer.

Then, from “Controlling Data In Kernel Space”:

Placing two of these vm_map_copy structs next to another, then corrupting the first one’s size to read the second one’s header allows you to leak the kdata pointer.

What if instead of placing two vm_map_copy structures one next to the other I place first a vm_map_copy and then a C++ object, then corrupt the vm_map_copy’s header to read into the C++ object? Whoo, I see. I leak the vtable pointer to userland. And where is the vtable located? In kernel/kernel extension text. Can you calculate this from userland? Sure you can!
Subtract the calculated value from the leaked value. What’s the result? If we ran this just before crashing to get kernel panic log shown in the first part of “Breaking KASLR”, the result would be 0x0000000007600000.

Gaining Code Execution – Again

Okay. Here we go again. We now have knowledge of two things we didn’t have before. The first is a pointer to user-controlled data in kernel address space, and the second is the kernel slide. Again, we use our heap overflow to corrupt the vtable pointer of a C++ object. Since we can store arbitrary data in the kernel address space and we know the pointer of this data, we can simply store a fake vtable and use it’s pointer. One question still stands: what will we execute? Due to kernel w^x you cannot just put the shellcode just next to the vtable, since the kernel heap is not executable. We need to do some more.

Bypassing Kernel W^X

This can be achieved fairly simply now that we have knowledge of the KASLR slide. All we need to do is to find some code that when executed will corrupt the stack pointer register to the address of our user-controlled data in kernel heap, execute that code, and once the stack corruption is done, it will return. By returning, it will take a value from the stack and set the instruction pointer to that value. By crafting what is called a ROP chain, you’ll be able to execute repeatedly small amounts of code, and with enough work you’ll be able to make this ROP chain do something useful to you. Since the ROP chain only uses code already inside the kernel, you do not need to be able to write your shellcode in an executable page. Just use what is already there, sitting in R-X page.

From a theoretical point of view, the kernel is now completely owned. All the security “features” we talked about at the beginning of this post have now been completely bypassed. It’s time to party like it’s 1990s 2011 again, with no exploit mitigations standing between us and privilege-escalated code execution in ring0.
The next blog post will contain code that implements the techniques described in this blog post.

NOTE: These techniques are not new. They have been used multiple times by different people, including myself. I’m simply trying to document them. Credit goes to whoever introduced these first, I suppose. Since I have no clue who did so, I’ll refrain from giving credit to anyone in particular. This also means that I take no credit for anything on this blog post.

25 thoughts on “Attacking the XNU Kernel For Fun And Profit – Part 2

  1. hi!,I really like your writing very a lot! percentage we keep in touch more approximately your post on AOL? I need a specialist in this space to resolve my problem. May be that’s you! Looking forward to see you.

  2. Thanks a lot for sharing this with all of us you really recognize what you are speaking approximately! Bookmarked. Kindly additionally visit my site =). We will have a link trade contract among us!

  3. Nice post. I was checking continuously this blog and I’m impressed! Very helpful information particularly the last part 🙂 I care for such info a lot. I was looking for this certain information for a long time. Thank you and good luck.

  4. I precisely needed to thank you so much yet again. I am not sure the things I might have gone through in the absence of the actual pointers contributed by you directly on such a question. This has been the troublesome case in my position, however , seeing this professional manner you managed it took me to leap with delight. Extremely thankful for this guidance and even believe you comprehend what an amazing job you were getting into educating people using your webpage. I am sure you’ve never met all of us.

  5. It¡¦s truly a great and useful piece of information. I am satisfied that you just shared this helpful information with us. Please stay us up to date like this. Thank you for sharing.

  6. Excellent blog right here! Also your website rather a lot up very fast! What host are you the usage of? Can I get your affiliate link for your host? I desire my website loaded up as fast as yours lol

  7. you’re in reality a just right webmaster. The web site loading speed is incredible. It seems that you are doing any unique trick. Furthermore, The contents are masterpiece. you have done a great process on this subject!

  8. Thank you for any other informative website. Where else may just I get that kind of information written in such an ideal approach?
    I have a project that I’m simply now working on, and I’ve been at the glance out for such information.

  9. In 1995, Mr. Rameshwar Dhayal started his construction business known as Jaipur Realty company worked on small, residential home building projects at first but soon began building larger homes. Jaipur Realty a civil construction and interior / exterior development company our expertise lies in : House / Building construction, All type Renovation work (Residential, Commercial, Industrial). We also take work for Masonry, Plastring, POP, false ceiling, Flooring, wooden work, steel fabrication work, wall painting, wooden polishing and many more other services related to interior/exterior work.We have high experience and skilled manpower, we only use superior quality material from genuine vendors. All the work and vision is managed by a staff having the experience of renovation more than 20 years and has been well supported by the well established systems

  10. We welcome you at Used Parts Jaipur.com! Here you can find the directory of Used Automobile parts which are efficient, reliable and compatible in their own terms. We have tied up with Jaipur’s most acknowledged and well established Automobile Dealers on which you can trust completely. At Used Parts Jaipur.com you can search for a reliable Auto Recycler with ease and can deal with used parts you are looking for. So begin a journey of used auto parts purchasing and selling with us.Used Parts is a online portal where a customer can find used parts for his vichele e.g. cars, trucks, jcb, jeep, buses, crane, motor parts, mechanical parts etc. located at jaipur city in India. We sell used parts to consumers looking for an inexpensive way to rebuild their vehicle. Visit our online website usedpartsjaipur.com today and start saving. We purchase used vehicles from insurance companies, private parties, and auctions. We acquire parts daily- thus our inventory is always changing- and odds are we can find the used auto part you are looking for

  11. Thanks a bunch for sharing this with all people you really recognise what you are talking approximately! Bookmarked. Please additionally visit my website =). We may have a hyperlink exchange contract among us!

Leave a Reply

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