Monday, November 24, 2014

pwn4fun Spring 2014 - Safari - Part II

Posted by Ian Beer


TL;DR

An OS X GPU driver trusted a user-supplied kernel C++ object pointer and called a virtual function. The IOKit registry contained kernel pointers which were used defeat kASLR. A kernel ROP payload ran Calculator.app as root using a convenient kernel API.


Overview of part I

We finished part I with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to load our own native library into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Safari renderer process on OS X by exploiting an integer truncation bug in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Safari javascript engine. Here in part II we’ll take a look at how sandboxing works on OS X, revise some OS X fundamentals and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n exploit two kernel bugs to launch Calculator.app running as root from inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Safari sandbox.


Safari process model

Safari’s sandboxing model is based on privilege separation. It uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKit2 framework to communicate between multiple separate processes which collectively form cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Safari browser. Each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se processes is responsible for a different part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser and sandboxed to only allow access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system resources it requires.

Specifically Safari is split into four distinct process families:
  • WebProcesses are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 renderers - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re responsible for actually drawing web pages as well as dealing with most active web content such as javascript
  • NetworkProcess is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process which talks to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 network
  • PluginProcesses are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processes which host native plugins like Adobe Flash
  • UIProcess is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unsandboxed parent of all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes and is responsible for coordinating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 activity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandboxed processes such that a webpage is actually displayed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can interact with

The Web, Network and Plugin process families are sandboxed. In order to understand how to break out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebProcess that we find ourselves in we’ve first got to understand how this sandbox is implemented.


OS X sandboxing primitives

OS X uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mandatory Access Control (MAC) paradigm to implement sandboxing, specifically it uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TrustedBSD framework. Use of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC sandboxing paradigm implies that whenever a sandboxed process tries to acquire access to some system resource, for example by opening a file or creating a network socket, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS will first check: Does this particular process have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right to do this?

An implementation of sandboxing using TrustedBSD has two parts: firstly, hooks must be added to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel code wherever a sandboxing decision is required. A TrustedBSD hook looks like this:


/* bsd/kern/uipc_syscalls.c */
int socket(struct proc *p, struct socket_args *uap, int32_t *retval)
{
#if CONFIG_MACF_SOCKET_SUBSET
if ((error = mac_socket_check_create(kauth_cred_get(), uap->domain,
   uap->type, uap->protocol)) != 0)
return (error);
#endif /* MAC_SOCKET_SUBSET */
...


That snippet of code is from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 socket syscall on OS X. If MAC support has been enabled at compile time 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 very first thing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 socket syscall implementation will do is call mac_socket_check_create, passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 credentials of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calling processes and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 domain, type and protocol of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested socket:


/* security/mac_socket.h */
int mac_socket_check_create(kauth_cred_t cred, int domain, int type, int protocol)
{
int error;

if (!mac_socket_enforce)
return 0;

MAC_CHECK(socket_check_create, cred, domain, type, protocol);
return (error);
}


Here we see that if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 enforcement of MAC on sockets hasn’t been globally disabled (mac_socket_enforce is a variable exposed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sysctl interface) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n this function falls through to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC_CHECK macro:


/* security/mac_internal.h */
#define MAC_CHECK(check, args...) do {     \
for (i = 0; i < mac_policy_list.staticmax; i++) {  \
mpc = mac_policy_list.entries[i].mpc;          \
...
if (mpc->mpc_ops->mpo_ ## check != NULL)       \
error = mac_error_select(           \
   mpc->mpc_ops->mpo_ ## check (args), \
   error);


This macro is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 core of TrustedBSD. mac_policy_list.entries (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first highlighted chunk) is a list of policies and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second highlighted chuck is TrustedBSD consulting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 policy. In actual fact a policy is nothing more than a C struct (struct policy_ops) containing function pointers (one per hook type) and consultation of a policy simply means calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right function pointer in that struct.

If that policy function returns 0 (or isn’t implemented at all by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 policy) 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 MAC check succeeds. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 policy function returns a non-zero value 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 MAC check fails and, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of this socket hook, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 syscall will fail passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 error code back up to userspace and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 socket syscall won’t be executed.

The second part of an implementation of sandboxing using TrustedBSD is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 provision of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se policy modules. Although TrustedBSD allows multiple policy modules to be present at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same time in practice on OS X cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s only one and it’s implemented in its own kernel extension: Sandbox.kext. When it's loaded Sandbox.kext registers itself as a policy with TrustedBSD by passing a pointer to its policy_ops structure. TrustedBSD adds this to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mac_policy_list.entries array seen earlier and will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n call into Sandbox.kext whenever a sandboxing decision is required.


Sandbox.kext and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X sandbox policy_ops

This paper from Dionysus Blazakis, this talk from Meder Kydyraliev and this reference from @osxreverser go into great detail about Sandbox.kext and its operation and usage.

Summarizing those linked resources, every process can have a unique sandbox profile. For (almost) every MAC hook type Sandbox.kext allows a sandbox profile to specify a decision tree to be used to determine 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 MAC check should pass or fail. This decision tree is expressed in a simple scheme-like DSL built from tuples of actions, operations and filters (for a more complete guide to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 syntax refer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 linked docs):


(action operation filter)


  • Actions determine whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a particular rule corresponds to passing or failing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC check. Actions are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 literals allow and deny.
  • Operations define which MAC hooks this rule applies to. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file-read operation allows restricting read access to files.
  • Filters allow a more granular application of operations, for example a filter applied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file-read operation could define a specific file which is or isn’t allowed.

Here’s a snippet from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebProcess sandbox profile to illustrate that:


(deny default (with partial-symbolication))
...
(allow file-read*
      ;; Basic system paths
      (subpath "/Library/Dictionaries")
      (subpath "/Library/Fonts")
      (subpath "/Library/Frameworks")
      (subpath "/Library/Managed Preferences")
      (subpath "/Library/Speech/Syncá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sizers")
      (regex #"^/private/etc/(hosts|group|passwd)$")
...
)


As you can see sandbox profiles are very readable on OS X. It’s usually quite clear what any particular sandbox profile allows and denies. In this example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 profile is using regular expressions to define allowed file paths (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a small regex matching engine in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel in AppleMatch.kext.)

Sandbox.kext also has a mechanism which allows userspace programs to ask for policy decisions. The main use of this is to restrict access to system IPC services, access to which isn’t mediated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel (so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s nowhere to put a MAC hook) but by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 userspace daemon launchd.


Enumerating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface of a sandboxed process

Broadly speaking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are two aspects to consider when enumerating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface reachable from within a particular sandbox on OS X:


  • Actions which are specifically allowed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox policy - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are easy to enumerate by looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox policy files.
  • Those actions which are allowed because eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Sandbox.kext policy_ops doesn’t implement cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hook callback or because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no hook in place at all.

The Safari WebProcess sandbox profile is located here:
/System/Library/StagedFrameworks/Safari/WebKit.framework/Versions/A/Resources/com.apple.WebProcess.sb

This profile uses an import statement to load cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of  /System/Library/Sandbox/Profiles/system.sb which uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 define statement to declare various broad sandboxing rulesets which define all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rules required to use complete OS X subsystems such as graphics or networking. Amongst ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Webprocess.sb profile uses (system-graphics) which is defined here in system.sb:


(define (system-graphics)
...
 (allow iokit-open
        (iokit-connection "IOAccelerator")
        (iokit-user-client-class "IOAccelerationUserClient")
        (iokit-user-client-class "IOSurfaceRootUserClient")
        (iokit-user-client-class "IOSurfaceSendRight"))
 )
)


This tells us that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebProcess sandbox has pretty much unrestricted access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GPU drivers. In order to understand what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iokit-user-client-class actually means and what this gives us access to we have to step back and take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 various parts of OS X involved in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operation of device drivers.


OS X kernel fundamentals

There are two great books I’d recommend to learn more about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X kernel: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 older but still relevant “Mac OS X Internals” by Amit Singh and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 more recent “Mac OS X and iOS Internals: To cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple’s Core” by Jonathan Levin.

The OS X wikipedia article contains a detailed taxonomic discussion of OS X and its place in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UNIX phylogenetic tree but for our purposes it’s sufficient to divide cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X kernel into three broad subsystems which collectively are known as XNU:

BSD

The majority of OS X syscalls are BSD syscalls. The BSD-derived code is responsible for things like file systems and networking.

Mach

Originally a research microkernel from CMU mach is responsible for many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low-level idiosyncrasies of OS X. The mach IPC mechanism is one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most fundamental parts of OS X but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach kernel code is also responsible for things like virtual memory management.
Mach only has a handful of dedicated mach syscalls (mach calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m traps) and almost all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se only exist to support cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach IPC system. All furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r interaction with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach kernel subsystems from userspace is via mach IPC.

IOKit

IOKit is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 framework used for writing device drivers on OS X. IOKit code is written in C++ which brings with it a whole host of new bug classes and exploitation possibilities. We'll return to a more detailed discussion of IOKit later.


Mach IPC

If you want to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 permissions of a memory mapping in your process, talk to a device driver, render a system font, symbolize a crash dump, debug anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r process or determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current network connectivity status cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n on OS X behind cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scenes you’re really sending and receiving mach messages. In order to find and exploit bugs in all those things it’s important to understand how mach IPC works:


Messages, ports and queues

Mach terminology can be a little unclear at times and OS X doesn’t ship with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 man pages for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach APIs (but you can view cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m online here.)

Fundamentally mach IPC is message-oriented protocol. The messages sent via mach IPC are known as mach messages. Sending a mach message really means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message gets enqueued into a kernel-maintained message queue known as a mach port.

Only one process can dequeue messages from a particular port. In mach terminology this process has a receive-right for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 port. Multiple processes can enqueue messages to a port - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se processes hold send-rights to that port.

Within a process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se send and receive rights are called mach port names. A mach port name is used to index a per-process mapping between mach port names and message queues (akin to how a process-local UNIX file descriptor maps to an actual file):





In this diagram we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process with PID 123 has a mach port name 0xabc. It’s important to notice that this Mach port name only has a meaning within this process - we can see that in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel structure for this process 0xabc is just a key which maps to a pointer to a message queue.

When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process with PID 456 tries to dequeue a message using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach port name 0xdef cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel uses 0xdef to index that process’s map of mach ports such that it can find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct message queue from which to dequeue a message.


Mach messages

A single mach message can have up to four parts:
  • Message header - this header is mandatory and specifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 port name to send cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message to as well as various flags.
  • Kernel processed descriptors - this optional section can contain multiple descriptors which are parts of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message which need to be interpreted by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.
  • Inline data - this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 inline binary payload.
  • Audit trailer - The message receiver can request that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel append an audit trailer to received messages.





When a simple mach message containing no descriptors is sent it will first be copied entirely into a kernel heap-allocated buffer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. A pointer to that copy is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n appended to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct mach message queue and when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process with a receive right to that queue dequeues that message cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message gets copied into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receiving process.


Out-of-line memory

Copying large messages into and out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel is slow, especially if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 messages are large. In order to send large amounts of data you can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “out-of-line memory” descriptor. This enables cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message sender to instruct cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel to make a copy-on-write virtual memory copy of a buffer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receiver process when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 message is dequeued.

Bi-directional messages

Mach IPC is fundamentally uni-directional. In order to build a two-way IPC mechanism mach IPC allows for messages to carry port rights. In a mach message, along with binary data you can also send a mach port right.

Mach IPC is quite flexible when it comes to sending port rights to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes. You can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local_port field of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mach message header, use a port descriptor or use an OOL-ports descriptor. There are a multitude of flags to control exactly what rights should be transferred, or if new rights should be created during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 send operation (it’s common to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAKE_SEND flag which creates and sends a new send right to a port which you hold cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receive right for.)


Bootstrapping Mach IPC

There’s a fundamental bootstrapping problem with mach IPC: how do you get a send right to a port for which anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r process has a receive right without first sending cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m a message (thus encountering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same problem in reverse.)

One way around this could be to allow mach ports to be inherited across a fork() akin to setting up a pipe between a parent and child process using socketpair(). However, unlike file descriptors, mach port rights are not inherited across a fork so you can’t implement such a system.

Except, some mach ports are inherited across a fork! These are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special mach ports, one of which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bootstrap port. The parent of all processes on OS X is launchd, and one of its roles is to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 default bootstrap port which will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be inherited by every child.


Launchd

Launchd holds cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receive-right to this bootstrap port and plays cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 role of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bootstrap server, allowing processes to advertise named send-rights which ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes can look up. These are OS X Mach IPC services.


MIG

We’re now at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point where we can see how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel and userspace Mach IPC systems use a few hacks to get bootstrapped such that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re able to send binary data. This is all that you get with raw Mach IPC.

MIG is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mach Interface Generator and it provides a simple RPC (remote procedure call) layer on top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 raw mach message IPC. MIG is used by all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mach kernel services and many userspace services.

MIG interfaces are declared in .defs files. These use a simple Interface Definition Language which can define function prototypes and simple data structures. The MIG tool compiles cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 .defs into C code which implements all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 required argument serialization/deserialization.

Calling a MIG RPC is completely transparent, it’s just like calling a regular C function and if you’ve ever programed on a Mac you’ve almost certainly used a MIG generated header file.


IOKit

As mentioned earlier IOKit is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 framework and kernel subsystem used for device drivers. All interactions with IOKit begin with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit master port. This is anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r special mach port which allows access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry. devices.defs is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relevant MIG definition file. The Apple developer documentation describes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry in great detail.

The IOKit registry allows userspace programs to find out about available hardware. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, device drivers can expose an interface to userspace by implementing a UserClient.

The main way which userspace actually interacts with an IOKit driver's UserClient is via cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 io_connect_method MIG RPC:


type io_scalar_inband64_t = array[*:16] of uint64_t;
type io_struct_inband_t   = array[*:4096] of char;

routine io_connect_method(
 connection            : io_connect_t;
 in    selector        : uint32_t;

 in    scalar_input    : io_scalar_inband64_t;
 in    inband_input    : io_struct_inband_t;
 in    ool_input      : mach_vm_address_t;
 in    ool_input_size  : mach_vm_size_t;

 out   inband_output   : io_struct_inband_t, CountInOut;
 out   scalar_output   : io_scalar_inband64_t, CountInOut;
 in    ool_output      : mach_vm_address_t;
 inout ool_output_size : mach_vm_size_t
);


This method is wrapped by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKitUser library function IOConnectCallMethod.

The kernel implementation of this MIG API is in IOUserClient.cpp in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function 

is_io_connect_method:

  kern_return_t is_io_connect_method
   (
    io_connect_t connection,
    uint32_t selector,
    io_scalar_inband64_t scalar_input,
    mach_msg_type_number_t scalar_inputCnt,
    io_struct_inband_t inband_input,
    mach_msg_type_number_t inband_inputCnt,
    mach_vm_address_t ool_input,
    mach_vm_size_t ool_input_size,
    io_struct_inband_t inband_output,
    mach_msg_type_number_t *inband_outputCnt,
    io_scalar_inband64_t scalar_output,
    mach_msg_type_number_t *scalar_outputCnt,
    mach_vm_address_t ool_output,
    mach_vm_size_t *ool_output_size
    )
   {
       CHECK( IOUserClient, connection, client );
       
       IOExternalMethodArguments args;
...     
       args.selector = selector;
       
       args.scalarInput = scalar_input;
       args.scalarInputCount = scalar_inputCnt;
       args.structureInput = inband_input;
       args.structureInputSize = inband_inputCnt;
...
       args.scalarOutput = scalar_output;
       args.scalarOutputCount = *scalar_outputCnt;
       args.structureOutput = inband_output;
       args.structureOutputSize = *inband_outputCnt;     
...
       ret = client->externalMethod( selector, &args );


Here we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code fills in an IOExternalMethodArguments structure from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arguments passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MIG RPC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ::externalMethod method of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOUserClient.

What happens next depends on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s IOUserClient subclass. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver overrides externalMethod cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n this calls straight into driver code. Typically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 selector argument to IOConnectCallMethod would be used to determine what function to call, but if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subclass overrides externalMethod it’s free to implement whatever method dispatch mechanism it wants. However if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver subclass doesn’t override externalMethod cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOUserClient implementation of it will call getTargetAndMethodForIndex passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 selector argument - this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method which most IOUserClient subclasses override - it returns a pointer to an IOExternalMethod structure:


struct IOExternalMethod {
   IOService *  object;
   IOMethod     func;
   IOOptionBits flags;
   IOByteCount  count0;
   IOByteCount  count1;
};


Most drivers have a simple implementation of getTargetAndMethodForType which uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 selector argument to index an array of IOExternalMethod structures. This structure contains a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method to be invoked (and since this is C++ this isn’t actually a function pointer but a pointer-to-member-method which means things can get very fun when you get to control it! See cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug report for CVE-2014-1379 in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Project Zero bugtracker for an example of this.)

The flags member is used to define what mixture of input and output types cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ExternalMethod supports and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 count0 and count1 fields define cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number or size in bytes of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input and output arguments. There are various shim functions which make sure that func is called with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct prototype depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 declared number and type of arguments.


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

At this point we know that when we call IOConnectCallMethod what really happens is that C code auto-generated by MIG serializes all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arguments into a data buffer which is wrapped in a mach message which is sent to a mach port we received received from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry which we knew how to talk to because every process has a special device port. That message gets copied into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel where more MIG generated C code deserializes it and calls is_io_connect_method which calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s externalMethod virtual method.


Writing an IOKit fuzzer

When auditing code alongside manual analysis it’s often worth writing a fuzzer. As soon as you’ve understood where attacker-controlled data could enter a system you can write a simple piece of code to throw randomness at it. As your knowledge of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code improves you can make incremental improvements to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer, allowing it to explore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code more deeply.

IOConnectCallMethod is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 perfect example of a API where this applies. It’s very easy to write a simple fuzzer to make random IOConnectCallMethod calls. One approach to slightly improve on just using randomness is to try to mutate real data. In this case, we want to mutate valid arguments to IOConnectCallMethod. Check out this talk from Chen Xiaobo and Xu Hao about how to do exactly that.


DYLD interposing

dyld is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X dynamic linker. Similar to using LD_PRELOAD on linux dyld supports dynamic link time interposition of functions. This means we can intercept function calls between different libraries and inspect and modify arguments.

Here’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 complete IOConnectCallMethod fuzzer interpose library I wrote for pwn4fun:


#include
#include
#include
#include
#include

int maybe(){
 static int seeded = 0;
 if(!seeded){
   srand(time(NULL));
   seeded = 1;
 }
 return !(rand() % 100);
}

void flip_bit(void* buf, size_t len){
 if (!len)
   return;
 size_t offset = rand() % len;
 ((uint8_t*)buf)[offset] ^= (0x01 << (rand() % 8));
}

kern_return_t
fake_IOConnectCallMethod(
 mach_port_t connection,
 uint32_t    selector,
 uint64_t   *input,
 uint32_t    inputCnt,
 void       *inputStruct,
 size_t      inputStructCnt,
 uint64_t   *output,
 uint32_t   *outputCnt,
 void       *outputStruct,
 size_t     *outputStructCntP)
{
 if (maybe()){
   flip_bit(input, sizeof(*input) * inputCnt);
 }

 if (maybe()){
   flip_bit(inputStruct, inputStructCnt);
 }

 return IOConnectCallMethod(
   connection,
   selector,
   input,
   inputCnt,
   inputStruct,
   inputStructCnt,
   output,
   outputCnt,
   outputStruct,
   outputStructCntP);
}

typedef struct interposer {
 void* replacement;
 void* original;
} interpose_t;

__attribute__((used)) static const interpose_t interposers[]
 __attribute__((section("__DATA, __interpose"))) =
   {
     { .replacement = (void*)fake_IOConnectCallMethod,
       .original    = (void*)IOConnectCallMethod
     }
   };

Compile that as a dynamic library:

$ clang -Wall -dynamiclib -o flip.dylib flip.c -framework IOKit -arch i386 -arch x86_64


and load it:

$ DYLD_INSERT_LIBRARIES=./flip.dylib hello_world


1% of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time this will flip one bit in any struct input and scalar input to an IOKit external method. This was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer which found cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug used to get kernel instruction pointer control for pwn4fun, and it found it well before I had any clue how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Intel GPU driver worked at all.


IntelAccelerator bug

Running cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer shown above with any program using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GPU lead within seconds to a crash in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following method in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AppleIntelHD4000Graphics kernel extension at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 instruction at offset 0x8BAF:


IGAccelGLContext::unmap_user_memory( ;rdi == this
  IntelGLUnmapUserMemoryIn *, ;rsi
  unsigned long long) ;rdx
__text:8AD6
__text:8AD6 var_30 = qword ptr -30h
...
__text:8AED  cmp   rdx, 8
__text:8AF1  jnz   loc_8BFB
__text:8AF7  mov   rbx, [rsi] ;rsi points to controlled data
__text:8AFA  mov   [rbp+var_30], rbx ;rbx completely controlled
...
__text:8BAB  mov   rbx, [rbp+var_30]
__text:8BAF  mov   rax, [rbx]        ;crash
__text:8BB2  mov   rdi, rbx
__text:8BB5  call  qword ptr [rax+140h]


Looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cross references to this function in IDA Pro we can see that unmap_user_memory is selector 0x201 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IGAccelGLContent user client. This external method has one struct input so on entry to this function rsi points to controlled data (and rdx contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of that struct input in bytes.)

At address 0x8af7 this function reads cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first 8 bytes of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct input as a qword and saves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in rbx. At this point rbx is completely controlled. This controlled value is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n saved into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local variable var_30. Later at 0x8bab this value is read back into rbx, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n at 0x8baf that controlled value is dereferenced without any checks leading to a crash. If that dereferences doesn't crash however, 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 qword value at offset 0x140 from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 read value will be called.

In ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r words, this external method is treating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct input bytes as containing a pointer to a C++ object and it’s calling a virtual method of that object without checking 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 pointer is valid. Kernel space is just trusting that userspace will only ever pass a valid kernel object pointer. So by crafting a fake IOKit object and passing a pointer to it as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct input of selector 0x201 of IGAccelGLContent we can get kernel instruction pointer control! Now what?


SMEP/SMAP

SMEP and SMAP are two CPU features designed to make exploitation of this type of bug trickier.

Mavericks supports Supervisor Mode Execute Prevention which means that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processor is executing kernel code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cpu will fault if it tries to execute code on pages belonging to userspace. This prevents us from simply mapping an executable kernel shellcode payload at a known address in userspace and getting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel to jump to it.

The generic defeat for this mitigation is code-reuse (ROP). Racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than diverting execution directly to shellcode in userspace instead we have to divert it to existing executable code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. By “pivoting” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pointer to controlled data we can easily chain togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r multiple code chunks and eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r turn off SMEP or execute an entire payload just in ROP.

The second generic mitigation supported at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CPU level is Supervisor Mode Access Prevention. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name suggests this prevents kernel code from even reading user pages directly. This would mean we’d have to be able to get controlled data at a known location in kernel space for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake IOKit object and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP stack since we wouldn’t be able to dereference userspace addresses, even to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.

However, Mavericks doesn’t support SMAP so this isn’t a problem, we can put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake IOKit object, vtable and ROP stack in userspace.


kASLR

To write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP stack we need to know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel code we’re planning to reuse. On OS X kernel address space layout randomisation means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are 256 different addresses where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel code could be located, one of which is randomly chosen at boot time. Therefore to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addresses of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable code chunks we need some way to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 distance kASLR has shifted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code in memory (this value is known as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kASLR slide.)


IOKit registry

We briefly mentioned earlier that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry allows userspace programs to find out about hardware, but what does that actually mean? The IOKit registry is really just a place where drivers can publish (key:value) pairs (where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 key is a string and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value something equivalent to a CoreFoundation data type.) The drivers can also specify that some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se keys are configurable which means userspace can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry API to set new values.

Here are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MIG RPCs for reading and settings IOKit registry values:


routine io_registry_entry_get_property(
         registry_entry      : io_object_t;
     in  property_name      : io_name_t;
     out properties          : io_buf_ptr_t, physicalcopy );

routine io_registry_entry_set_properties(
         registry_entry      : io_object_t;
     in  properties          : io_buf_ptr_t, physicalcopy;
     out result              : kern_return_t );


And here are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 important parts of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel-side implementation of those functions, firstly, for setting a property:


kern_return_t is_io_registry_entry_set_properties
io_object_t registry_entry,
   io_buf_ptr_t properties,
   mach_msg_type_number_t propertiesCnt,
   kern_return_t * result){
...       

 obj = OSUnserializeXML( (const char *) data, propertiesCnt );
 ...
#if CONFIG_MACF
 else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
                                                registry_entry,
obj))
   res = kIOReturnNotPermitted;
#endif
 else
   res = entry->setProperties( obj );
...


and secondly, for reading a property:


kern_return_t is_io_registry_entry_get_property(
   io_object_t registry_entry,
   io_name_t property_name,
   io_buf_ptr_t *properties,
   mach_msg_type_number_t *propertiesCnt ){
 ...
 obj = entry->copyProperty(property_name);
 if( !obj)
   return( kIOReturnNotFound );
       
 OSSerialize * s = OSSerialize::withCapacity(4096);
  ...
 if( obj->serialize( s )) {
   len = s->getLength();
   *propertiesCnt = len;
   err = copyoutkdata( s->text(), len, properties );
...


These functions are pretty simple wrappers around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 setProperties and copyProperty functions implemented by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 drivers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves.

There’s one very important thing to pick up on here though: in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 is_io_registry_entry_set_properties function cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a MAC hook, highlighted here in red, which allows sandbox profiles to restrict cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to set IOKit registry values. (This hook is exposed by Sandbox.kext as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iokit-set-properties operation.) Contrasts this with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 is_io_registry_entry_get_property function which has no MAC hook. This means that read access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry cannot be restricted. Every OS X process has full access to read every single (key:value) pair exposed by every IOKit driver.


Enumerating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iokit registry

OS X ships with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ioreg tool for exploring cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOKit registry on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line. By passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 -l flag we can get ioreg to enumerate all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registry keys and dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir values. Since we’re looking for kernel pointers, lets grep cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 output looking for a byte pattern we’d expect to see in a kernel pointer:


$ ioreg -l | grep 80ffffff
   |   "IOPlatformArgs" =<00901d2880ffffff00c01c2880ffffff90fb222880ffffff0000000000000000>


That looks an awful lot like a hexdump of some kernel pointers :)

Looking for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "IOPlatformArgs" string in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XNU source code we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se pointers is actually 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 DeviceTree that’s passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel at boot. And it just so happens that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same kASLR slide that gets applied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel image also gets applied to that DeviceTree pointer, meaning that we can simply subtract a constant from this leaked pointer to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 runtime load address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel allowing us to rebase our ROP stack.

Check out this blog post from winocm for a lot more insight into this bug and its applicability to iOS.


OS X kernel ROP pivot

Looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 disassembly of unmap_user_memory we can see that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 controlled virtual method is called cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rax register points to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable which we've put in userspace. The pointer at offset 0x140h will be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function pointer that gets called which makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable a convenient place for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP stack. We just need to find a sequence of instructions which will move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of rax into rsp. The /mach_kernel binary has following instruction sequence:


   push rax
   add [rax], eax
   add [rbx+0x41], bl
   pop rsp
   pop r14
   pop r15
   pop rbp
   ret


This will push cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable address on to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first entry in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable and write a byte to rbx+0x41. rbx will be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 this pointer of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake IOKit object which we control and have pointed into userspace so neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se writes will crash. pop rsp cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n pops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack into rsp - since we just pushed rax on to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack this means that rsp now points to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable in userspace. The code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n pops values for r14, r15 and rbp cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n returns meaning that we can place a full ROP stack in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake IOKit object.


Payload and continuation

The OS X kernel function KUNCExecute is a really easy way to launch GUI applications from kernel code:


kern_return_t KUNCExecute(char executionPath[1024], int uid, int gid)


The payload for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pwn4fun exploit was a ROP stack which called this, passing a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string “/Applications/Calculator.app/Contents/MacOS/Calculator” as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executionPath and 0 and 0 as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uid and gid parameters. This launches cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X calculator as root :-)

Take a look at this exploit for this ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r IOKit bug which takes a slightly different approach by using a handful of ROP gadgets to first disable SMEP cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n call a more complicated shellcode payload in userspace. And if you're still running OS X Mavericks or below cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n why not try it out?

After executing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel payload we can call cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel function thread_exception_return to return back to usermode. If we just do this however it will appear as if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole system has frozen. The kernel payload has actually run (and we can verify this by attaching a kernel debugger) but we can no longer interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system. This is because before we got kernel code execution unmap_user_memory took two locks - if we don’t drop those locks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r functions will be able to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GPU driver grinds to a halt. Again, check out that linked exploit above to see some example shellcode which drops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 locks.

Conclusion

The actual development process of this sandbox escape was nothing like as linear as this writeup made it seem. There were many missed turns and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r bugs which looked like far too much effort to exploit. Naturally cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se were reported to Apple too, just in case.


A few months after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conclusion of pwn4fun 2014 I decided to take anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r look at GPU drivers on OS X, this time focusing on manual analysis. Take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following bug reports for PoC code and details of all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 individual bugs: CVE-2014-1372, CVE-2014-1373, CVE-2014-1376, CVE-2014-1377, CVE-2014-1379, CVE-2014-4394, CVE-2014-4395, CVE-2014-4398, CVE-2014-4401, CVE-2014-4396, CVE-2014-4397, CVE-2014-4400, CVE-2014-4399, CVE-2014-4416, CVE-2014-4376, CVE-2014-4402