Last October I released ida_kernelcache, an IDA Pro toolkit for analyzing iOS kernelcache files. My goal was to make working with kernelcaches in IDA a bit easier by improving segment names, automatically converting some pointers into offsets, symbolicating virtual methods and virtual method tables, and automatically renaming stub functions in kexts. Today, I’m releasing what I’ve found to be the most useful part of the toolkit thus far: automatically reconstructing class layouts and C structs via data flow analysis.
Way back in October of 2017, I discovered CVE-2017-13868, a kernel information leak in XNU that was
quite fun to analyze and exploit. While browsing the XNU source code, I noticed that the function
ctl_ctloutput didn’t check the return value of a call to
sooptcopyin. This immediately caught
my attention because error checking in the kernel is very important: poor error checking is a
frequent source of security bugs. In this case, failing to check the return value opened a race
window that could allow a privileged process to read an arbitrary amount of uninitialized kernel
Part of effective security research is having the right tools to analyze vulnerabilities. Apple allows users to develop kernel extensions and debug the kernel on macOS, but neither is supported on iOS. This post explains how I developed memctl, a kernel introspection tool for macOS and iOS that I’ve been using for the past year to analyze the kernel.
Memctl uses the kernel task port to reliably read and write kernel memory and to reliably call arbitrary kernel functions with arbitrary arguments on both macOS and iOS. Other useful features are implemented on top of this basic functionality, mostly convenience routines to call kernel functions that would otherwise be difficult to find or call. Memctl’s functionality is provided both as a library (called libmemctl) and as a command-line tool.
Coincidentally, Ian Beer described how he developed his own kernel memory debugger in Exception-oriented exploitation on iOS, which was published late into my work on memctl. To me this shows how useful such a tool could be. While I developed memctl primarily for my own use, I am open-sourcing it in case someone else finds my work useful.
Late in 2015 I was looking for a way to create an instance of an IOKit user client with a visible
NULL pointer dereference when I discovered something intriguing: the default implementation of
IOService::newUserClient checks the
IOUserClientClass property on the service when determining
what user client class to allocate. This caught my attention because IOKit provides an API to set
arbitrary properties on an
IOService from user space. If any
IOService allowed setting the
IOUserClientClass property, that would create an opportunity for kernel code execution.
I immediately started looking for
setProperty calls with attacker-controlled keys and values.
Amazingly, I found that
IOHIDevice would iterate the attacker-supplied properties dictionary and
indiscriminately add each key-value pair to its own set of properties. This post is about how I
leveraged this vulnerability to gain read/write access to physical memory from user space, and how
this awesome primitive can be used to get fully reliable kernel code execution.
I reported this issue to Apple in January of 2016, and it was assigned CVE-2016-1825. It was fixed in OS X El Capitan 10.11.5. A proof-of-concept exploit for this vulnerability (and the variant CVE-2016-7617) is available in my physmem repository on GitHub. This vulnerability is not present on iOS.
Among the bugs that Apple patched in OS X 10.11.5 is CVE-2016-1828, a use-after-free I discovered late last year while looking through the kernel source. Combined with CVE-2016-1758, an information leak patched in 10.11.4, this vulnerability can be used to execute arbitrary code in the kernel. In this post I’ll document how I created rootsh, a local privilege escalation for OS X 10.10.5 (14F27).
CVE-2016-1828 is a use-after-free in the function
passing a crafted binary blob to this function, it is possible to invoke a
virtual method on an object with a controlled vtable pointer. I leveraged the
use-after-free to create a NULL pointer dereference, allowing the vtable and
the ROP stack to live in user space.
CVE-2016-1758 is a kernel stack disclosure in the function
bytes of uninitialized kernel stack are copied to user space. Those bytes can
be initialized to a known location within the kernel text segment by invoking a
system call prior to triggering the disclosure. After leaking the text segment
pointer, the kernel slide can be computed by subtracting the base address of
that particular text segment location from the leaked address.