11.07.2015 Views

Advanced Mac OS X Rootkits [PDF - Black Hat

Advanced Mac OS X Rootkits [PDF - Black Hat

Advanced Mac OS X Rootkits [PDF - Black Hat

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

ADVANCED MAC <strong>OS</strong> X ROOTKITSDINO A. DAI ZOVIDDZ@THETA44.ORGAbstract. The <strong>Mac</strong> <strong>OS</strong> X kernel (xnu) is a hybrid BSD and <strong>Mac</strong>hkernel. While Unix-oriented rootkit techniques are pretty well known,<strong>Mac</strong>h-based rootkit techniques have not been as thoroughly publiclyexplored. This paper covers a variety of rootkit techniques for bothuser-space and kernel-space rootkits using unique and poorly understoodor documented <strong>Mac</strong> <strong>OS</strong> X and <strong>Mac</strong>h features.1. IntroductionRootkit techniques affecting FreeBSD are well known and documented([4]). Many of these techniques also apply directly to <strong>Mac</strong><strong>OS</strong> X since it shares a good deal of code with FreeBSD. This research,however, focuses on rootkit techniques that use or abuse unique featuresof the <strong>Mac</strong>h functionality in the <strong>Mac</strong> <strong>OS</strong> X kernel.This paper is organized as follows. First, some background is givenon <strong>Mac</strong>h abstractions, IPC, and RPC. The body of the paper proceedsin describing injecting code into running processes, injecting new inkernelRPC subsystems, transparent remote control of a compromisedsystem via <strong>Mac</strong>h IPC, and detecting hidden kernel rootkits. Finally,the paper concludes with some commentary on future directions andgives the reader instructions on how to obtain the proof-of-concepttools described in this paper.2. BackgroundThe <strong>Mac</strong> <strong>OS</strong> X kernel (xnu) is an operating system kernel of mixedlineage, combining the older research-oriented <strong>Mac</strong>h microkernel withthe more traditional and modern FreeBSD monolithic kernel. The<strong>Mac</strong>h microkernel combines a powerful abstraction, <strong>Mac</strong>h messagebasedinterprocess communication (IPC) with a number of cooperatingservers to form the core of an operating system. The <strong>Mac</strong>h microkernelis responsible for managing separate tasks, each in their own separateaddress spaces and consisting of multiple threads. A number of defaultDate: July 24, 2009.


2 DINO A. DAI ZOVI DDZ@THETA44.ORGservers also provide virtual memory paging, a system clock, and othermiscellaneous low-level services.The <strong>Mac</strong>h microkernel alone, however, is not enough to implementa modern operating system. In particular, it has no notion of users,groups, or even files. In order to provide this functionality, the <strong>Mac</strong> <strong>OS</strong>X kernel includes a graft of the FreeBSD kernel. The top-half of theFreeBSD kernel (system call handlers, file systems, networking, etc)was ported to run on top of the <strong>Mac</strong>h microkernel. In order to addressthe performance concerns with excessive IPC messaging between kernelcomponents, both kernels exist in the same privileged address space.However, in most respects, the <strong>Mac</strong>h API visible from kernel code isthe same as the <strong>Mac</strong>h API visible from user processes.The <strong>Mac</strong>h kernel deals with a number of core abstractions: the host,task, thread, and ports that represent them. The <strong>Mac</strong>h host representsa computer system that is capable of running tasks. Each task encapsulatesa number of resources, including a virtual memory address space,one or more threads of execution control, and an IPC space. The <strong>Mac</strong>hkernel, tasks, and threads all communicate with each other throughports. A port is a unidirectional, sequenced, and structured data channelthat is capable of transmitting messages. Each port in a task’s IPCspace is referred to by a task-specific name. Different tasks may referto the same port via different names. Access to a port is governed bya task possessing defined rights on it. Multiple tasks may have rightsto send messages on a port, however only one task may have rights toreceive messages on it. In addition to sending data, tasks may transmitport rights through messages to other tasks. This system of ports andport rights forms <strong>Mac</strong>h’s capability-based security model.Unidirectional IPC is only of limited use. In order to provide a moreflexible system, <strong>Mac</strong>h provides a Remote Procedure Call (RPC) systemon top of <strong>Mac</strong>h IPC. Tasks may use RPC to interact with other tasks onthe same host. Tasks that primarily perform actions on behalf of othertasks are referred to as servers. <strong>Mac</strong>h-based systems commonly provideMiG, the <strong>Mac</strong>h Interface Generator to aid in constructing RPC clientsand servers. MiG takes a definition file specifying the RPC interface(referred to as a subsystem) and creates both client and server stubfunctions to automatically handle the marshalling of data into andfrom <strong>Mac</strong>h messages. MiG-generated client stubs are actually usedin most of the <strong>Mac</strong>h API to communicate with MiG-generated serverstubs executing within the kernel.


ADVANCED MAC <strong>OS</strong> X ROOTKITS 33. <strong>Mac</strong>h InjectionThe <strong>Mac</strong>h API supports a high-level of control over other tasks andthreads. With access to another task’s control port, a controlling taskmay allocate, deallocate, read, and write memory within the task. Itmay also create, suspend, and kill threads within the controlled task.These operations are sufficient to map new code into the remote taskand create a new thread to execute that code. There are, however,some complications with this.First, the injected code will not be able to call many system APIs.The code will be executing within a ”naked” <strong>Mac</strong>h thread and manysystem functions assume that all threads are P<strong>OS</strong>IX threads. Second,the injected code may need to be linked in order to call system libraries.Purely injected code is essentially limited to the level of functionalityof common exploit payloads used in memory corruption exploits.In order to address these shortcomings, direct <strong>Mac</strong>h thread injectionis simply used to call functions loaded in the remote processes addressspace. A small bit of trampoline code is injected in order to promotethe ”naked” <strong>Mac</strong>h thread into a full P<strong>OS</strong>IX thread so that the fullrange of standard library functions may be called. In addition, we usea unique feature of <strong>Mac</strong>h in order to obtain the return value of thefunction call in the remote address space. In addition to setting upthe thread, the injected trampoline sets a bogus stack return addressintended to make the thread crash in a deterministic way. Prior tostarting the thread, the controlling task registers itself as an exceptionhandler for that thread. By doing so, it is notified about exceptions inthe thread before the owning task is. This allows the controlling taskto handle the exception and terminate the thread without disturbingthe rest of the task. When the injected thread crashes at the bogusreturn address, the return value from the function is obtained fromthe appropriate CPU register in the thread state. By combining thesesteps, the controlling task is able to call arbitrary functions in thetarget task with chosen arguments and obtain the returned value ofthe called function.Using this technique, dlopen() is called in the remote process in orderto properly load and link a bundle from disk. After loading, dlsym()is called to resolve the address of the run() symbol exported from thebundle. Finally, this function is called in order to run the injectedbundle in the remote task.For more complete details on this technique, see the author’s injectbundletool (available as described in Section 7) and Chapter 11 of The<strong>Mac</strong> Hacker’s Handbook [5].


4 DINO A. DAI ZOVI DDZ@THETA44.ORG4. Kernel RPC Subsystem InjectionA number of <strong>Mac</strong>h RPC servers exist within the kernel. The <strong>Mac</strong>hIPC abstractions allow RPC servers to run in the kernel or user-mode<strong>Mac</strong>h tasks, often only requiring a recompile with different options toMiG. In <strong>Mac</strong> <strong>OS</strong> X Leopard, the <strong>Mac</strong>h clock, clock priv, host priv,host security, ledger, lock set, mach host, mach port, mach vm, processor,processor set, security, task, thread act, and vm map subsystemsare all implemented as kernel servers. <strong>Mac</strong> <strong>OS</strong> X adds a fewnew in-kernel <strong>Mac</strong>h servers for the IOKit and UserNotification systems.Running these servers in the kernel improves performance as thedelivery of <strong>Mac</strong>h IPC messages requires less mode switches betweenuser and kernel mode.In the xnu kernel, IPC messages received by the kernel are routed toin-kernel RPC servers through the mig_buckets hash table. This datastructure and the functions that operate on it are defined in the xnukernel source file osfmk/kern/ ipc_kobject.c. Each routine in the MiGsubsystem is inserted in the hash table by storing its routine identifier,function pointer, and maximum message size. Incoming messageshave their msgh_id header field set to the routine identifier and the kernelfunction ipc_kobject_server uses this field to find the RPC serverroutine to handle the request.While the mig_buckets hash table is statically initialized by the kernel,a rootkit can easily dynamically inject new subsystems into it,as described in [5] and shown in Figure 1. The injected or existingsubsystems can also be removed as shown in Figure 2.Just as easily as new subsystems are added or removed, existingsubsystems can be modified. The subsystems in this hash table performmany of the critical functions of the <strong>Mac</strong>h kernel, including task,thread, and memory management. A kernel-based rootkit could overwritethe routine pointers in this table in order to intercept messagesto these servers. The request messages and their replies could be modifiedin transit in order to modify the behavior of the in- kernel <strong>Mac</strong>hRPC server. In this respect, this technique is similar to how moretraditional rootkits intercept system calls by patching the system calltable on Unix-like operating systems or the System Service Table onWindows-based operating systems.5. <strong>Mac</strong>hiavelliHistorical <strong>Mac</strong>h-based operating systems often included the NetMessageServer [2]. The NetMessage Server transparently extended <strong>Mac</strong>hIPC across the network to other hosts. Each node ran a NetName


ADVANCED MAC <strong>OS</strong> X ROOTKITS 5int inject_subsystem ( const struct mig_subsystem * mig ){mach_msg_id_t h, i, r;// Insert each routine into mig_buckets hash tablefor (i = mig -> start ; i < mig -> end ; i ++) {mig_hash_t * bucket ;h = MIG_HASH (i);do {bucket = & mig_buckets [h % MAX_MIG_ENTRIES ];} while ( mig_buckets [h ++% MAX_MIG_ENTRIES ]. num !=0 &&h < MIG_HASH (i)+ MAX_MIG_ENTRIES );if ( bucket -> num == 0) {// We found a free spotr = mig -> start - i;}bucket -> num = i;bucket -> routine = mig -> routine [r]. stub_routine ;if (mig -> routine [r]. max_reply_msg )bucket -> size = mig -> routine [r]. max_reply_msg ;elsebucket -> size = mig -> maxsize ;}else {// Table was full , return an errorreturn -1;}}return 0;Listing 1. Inserting a new subsystem into the kernelserver hash tableserver that acted as a registry of ASCII string names to <strong>Mac</strong>h serverports for servers running on that host. Clients on a given node couldlookup ports registered in NetName servers on their local or remotehosts through their own local NetName server. The ports returned bythe local NetName server would in fact be ports to the local NetMessageserver. The NetMessage server would act as a proxy to the serverrunning on the remote host by sending and receiving messages acrossthe network. In <strong>Mac</strong> <strong>OS</strong> X, the functionality of the NetName server hasbeen subsumed by the Bootstrap Server run within launchd [7]. This


6 DINO A. DAI ZOVI DDZ@THETA44.ORGint remove_subsystem ( const struct mig_subsystem * mig ){mach_msg_id_t h, i;// Remove each routine exhaustively from the// mig_buckets tablefor (i = mig -> start ; i < mig -> end ; i ++) {for (h = 0; h < MAX_MIG_ENTRIES ; h ++) {if ( mig_buckets [h]. num == i) {bzero (& mig_buckets [h], sizeof ( mig_buckets [h ]));}}}}return 0;Listing 2. Removing a subsystem from the kernelserver hash tableBootstrap Server only holds ports for servers running on the local hostand provides no functionality analagous to the NetMessage Server.The high level of abstraction and control provided by <strong>Mac</strong>h IPCmakes it an ideal facility for remote control of a <strong>Mac</strong>h-based system.The author’s proof-of-concept rootkit, <strong>Mac</strong>hiavelli, does just this by implementinga facility similar in functionality to the NetMessage Server,however with the spirit and goals of a covert rootkit. <strong>Mac</strong>h IPC messagesare also programming language and byte ordering neutral. Whilethe current implementation uses the native MiG RPC client stub routinesto marshal IPC messages, an alternate implementation could marshallIPC messages by hand in any programming language.<strong>Mac</strong>hiavelli consists of a <strong>Mac</strong>h proxy server on the local controllinghost and a number of remote agent servers that run on remote compromisedhosts. On the controlling host, rootkit management utilitiesobtain a proxy <strong>Mac</strong>h port from the proxy server and use it just as anormal application would use a local <strong>Mac</strong>h port. For example, MiGgeneratedRPC client routines may be used with the proxy port inorder to execute the RPC request on the remote compromised host insteadof the local host. The <strong>Mac</strong>hiavelli proxy server receives the <strong>Mac</strong>hIPC message and transmits it over the network to the remote agent foractual processing by the destination RPC server.5.1. <strong>Mac</strong>hiavelli API. From the client software’s perspective, there islittle difference in performing <strong>Mac</strong>h RPC with local or remote servers.Normally, an application would obtain send rights to the local host,


# include # include < stdlib .h># include # include " machiavelli .h"ADVANCED MAC <strong>OS</strong> X ROOTKITS 7int main ( int argc , char * argv []){kern_return_t kr;machiavelli_t m = machiavelli_init ();mach_port_t port ;vm_size_t page_size ;machiavelli_connect_tcp (m, " 192.168.13.37 ", " 31337 ");port = machiavelli_get_port (m, H<strong>OS</strong>T_PORT );if (( kr = _host_page_size (port , & page_size )) !=KERN_SUCCESS ) {errx ( EXIT_FAILURE , " _host_page_size :␣%s",mach_error_string (kr ));}printf (" Host ␣ page ␣ size :␣%d\n", page_size );}return 0;Listing 3. Using <strong>Mac</strong>hiavelli to access a remote host porttask, or thread ports with mach_host_self(), mach_task_self(), ormach_thread_self() respectively. Alternatively, a privileged process mayobtain send rights for another unrelated task through the task_for_pid()BSD system call. A <strong>Mac</strong>hiavelli utility on the other hand obtains aproxy port for a remote port through the machiavelli_get_port() function.Consider the example in Figure 3. This small utility retrieves thepage size through a remote <strong>Mac</strong>hiavelli agent. In line 9, the local<strong>Mac</strong>hiavelli proxy is initialized. On line 13, the local proxy is instructedto connect to a remote <strong>Mac</strong>hiavelli agent via TCP on IP 192.168.13.37and port 31337. On line 15, the call to machiavelli_get_port() obtainsa proxy port for the <strong>Mac</strong>h host port on the remote system. This samefunction call can be used to obtain other special ports such as the hostprivileged port, IO master port, User Notification port, kernel task aswell as task ports for a given process identifier. Finally on line 17, theutility calls _host_page_size(), which is a MiG generated RPC client


8 DINO A. DAI ZOVI DDZ@THETA44.ORGstub in the mach_host subsystem. Normally, the first argument is ahost port obtained through mach_host_self(). In this case, we specifyour <strong>Mac</strong>hiavelli proxy port so that the <strong>Mac</strong>h RPC request is interceptedand handled by the RPC server on the remote system.5.2. Serializing and Deserializing <strong>Mac</strong>h IPC Messages. Serializingsimple <strong>Mac</strong>h messages to byte buffers suitable for transmissionover a network is straight-forward. In effect, they are already suitablefor transmission as-is with the simple step of translating remote portnames to local proxy port names. In both the <strong>Mac</strong>hiavelli Proxy and<strong>Mac</strong>hiavelli Agents, proxy ports are used to intercept <strong>Mac</strong>h messagesthat should be sent over the network. A local proxy port name withthe same port rights is substituted for any port name that exists in theremote port namespace. When a message is received on a proxy port,the original remote proxy name is placed in the message header beforeit is transmitted to the remote system. This is always performed forthe reply port that may be specified in the msgh_local_port field in the<strong>Mac</strong>h message header and, as described below, may also be performedon additional transferred port rights.Serializing complex <strong>Mac</strong>h messages is a little more involved. Complex<strong>Mac</strong>h messages include a number of descriptors for auxiliary outof-linedata, including additional <strong>Mac</strong>h ports, large memory buffers,and port arrays. An additional port right transferred via a <strong>Mac</strong>h messageis handled identically as the implicitly transferred port right forthe reply port specified in the message header. When out-of-line memoryis attached to a <strong>Mac</strong>h message, the descriptor contains the addressof the beginning and the size of the memory buffer. On a local system,the entire memory pages containing this memory buffer are remappedinto the task receiving the message. In order to transmit this memoryto a remote system, we append the memory buffer to end of the<strong>Mac</strong>h message. When the message is deserialized, this memory bufferis copied into freshly allocated memory pages. The buffer is not copiedto the beginning of the memory pages, though. As per the originalsemantics of the out-of-line memory transfers, the sent memory mustbe placed at the same offset from the beginning of a memory page asit was found at in the sending task. Also, depending on flags in theout-of-line memory descriptor and as passed by the message receiver,the memory pages may need to be allocated at the specified virtualaddress. A complex <strong>Mac</strong>h message may also include out-of-line portarrays. These arrays include both port names and port rights that havebeen transferred to the receiving task. In serialization, the contents ofthese arrays are appended to the message. In deserialization, the array


ADVANCED MAC <strong>OS</strong> X ROOTKITS 9is restored and the port name are replaced with the port names of localproxy ports created with the port rights specified in the port array.5.3. <strong>Mac</strong>hiavelli Proxy. The <strong>Mac</strong>hiavelli Proxy is the component of<strong>Mac</strong>hiavelli that runs locally on the controlling host. It is responsiblefor intercepting IPC messages on its proxy ports and transmittingthem to the remote <strong>Mac</strong>hiavelli Agent, which relays them to the remoteRPC server. A local application interacts with the <strong>Mac</strong>hiavelliProxy by initializing it, connecting to the remote <strong>Mac</strong>hiavelli Agent,and requesting send rights for remote ports through the <strong>Mac</strong>hiavelliAPI. The <strong>Mac</strong>hiavelli Proxy returns send rights for proxy ports whereit holds the receive rights. These ports are maintained in a port setthat it receives messages on. When the <strong>Mac</strong>hiavelli Proxy receives amessage on one of the ports in the set, it translates the message andtransmits the message to the remote <strong>Mac</strong>hiavelli Agent.While it currently runs as a background thread in any program thatuses the <strong>Mac</strong>hiavelli API, it could also have been implemented as abackground daemon with its server port registered in lookupd. Thiswould allow multiple control utilities to share a single connection tothe remote compromised system. This will be considered for futurework.5.4. <strong>Mac</strong>hiavelli Agents. The <strong>Mac</strong>h API is largely identical for usermodeand in-kernel <strong>Mac</strong>h servers. This allows us to easily implementboth user-mode and in-kernel <strong>Mac</strong>hiavelli agents. In addition, theserialized <strong>Mac</strong>h messages can be sent and received through any reliabledata channel giving us a number of options for implementation of<strong>Mac</strong>hiavelli Agents.The first proof-of-concept <strong>Mac</strong>hiavelli Agent is implemented as auser-mode process listening on a TCP socket. This is the simplestimplementation that still allows full remote control of the system. If theagent is run as root, it will have access to the task ports for any processvia the task_for_pid() system call. If task_for_pid() is called with apid argument of 0, it returns the kernel task control port. This portallows remote direct memory operations on kernel memory. Combinedwith remote access to the privileged host port, this allows effective andhigh-level control of the remote kernel, including the ability to load orunload kernel extensions, read or write kernel memory, and create orsuspend kernel threads.The user-mode TCP <strong>Mac</strong>hiavelli Agent supports a simple protocol.Upon establishing the connection, the server sends the client the remote<strong>Mac</strong>h port names for the host, task, and thread ports as well as a <strong>Mac</strong>h


10 DINO A. DAI ZOVI DDZ@THETA44.ORGport name of the <strong>Mac</strong>hiavelli RPC server. Following this, the server andclient communicate exclusively through serialized <strong>Mac</strong>h RPC messages.As described in [5], <strong>Mac</strong> <strong>OS</strong> X kernel rootkits may also take advantageof Network Kernel Extensions (NKE) APIs. The rootkit may usethese to intercept network traffic at multiple levels within the kernelnetwork stack, including ethernet frames directly from the network interfaceon through fully after IP defragmentation and TCP reassembly.Any number of these points may be used to implement a remote networkcovert channel for communication with an in-kernel <strong>Mac</strong>hiavelliAgent.6. Unloaking Kernel <strong>Rootkits</strong>While there have been few <strong>Mac</strong> <strong>OS</strong> X kernel rootkits observed in thewild, a number of proof-of-concept rootkits have been publicly releasedor presented. One of the first rootkits was nemo’s WeaponX rootkit[6]. Other similar rootkit techniques have been written about in Developing<strong>Mac</strong> <strong>OS</strong>X <strong>Rootkits</strong> [8] and The <strong>Mac</strong> Hacker’s Handbook [5].These rootkits share a common technique to hide themselves from kernelextension listings by removing themselves from the kernel modulelinked list (kmod).While a kernel module that is not present in the kmod linked listwill not be able to be enumerated or removed, it will still be visiblein memory. The memory allocated for the kernel module will also belisted in the kernel memory map. This memory map may be enumeratedby gaining access to the kernel task control port by passing a pidargument of 0 to task_for_pid() and calling mach_vm_region() on thattask port. This will enumerate the memory regions and their pageprotection permissions for the kernel memory address space.The <strong>Mac</strong>h host port also provides an interface to enumerate theloaded kernel modules, kmod_get_info(). This routine can be used toenumerate the loaded kernel modules, including the address and sizeof their loaded code. For proper usage of this function, see the sourcecode for kextstat [1].Detecting hidden rootkits is simply a matter of correlating <strong>Mac</strong>h-Oexecutable objects in the kernel address space with loaded code from eitherthe kernel or kernel modules enumerated through kmod_get_info().This is done by iterating across the memory regions allocated in thekernel and examining the beginning of them for a <strong>Mac</strong>h-O header. The<strong>Mac</strong>h-O headers will contain metadata describing its loaded code segment,which should represent the kernel or a loaded kernel module.Any <strong>Mac</strong>h-O executables that cannot be substantiated back to the


ADVANCED MAC <strong>OS</strong> X ROOTKITS 11kernel itself or a loaded kernel module should be considered suspicious.The suspicious <strong>Mac</strong>h-O executable objects can then dumped to diskfor further analysis.For an example implementation of this technique, see the author’sUncloak tool, available as described in Section 7.It should be noted, however, that this only identifies rootkits thathave not also hidden themselves from the kernel memory maps. Asdescribed above in Section 4, a rootkit may intercept IPC messagesto in-kernel servers and modify the replies. A rootkit that is aware ofthis detection technique could easily hide its memory regions from discoveryby intercepting messages to the appropriate mach_vm subsystemroutines.7. AvailabilityIn order to demonstrate these techniques, a number of proof-ofconcepttools have been developed. These tools will be made availableon the author’s web site [3] shortly after the <strong>Black</strong><strong>Hat</strong> USA 2009conference.• Inject Bundle: Inject a bundle loaded from disk into a runningprocess• iChatSpy: Swizzle iChat Objective-C methods in order to logIM messages• SSLSpy: Hook SecureTransport SSL functions to log SSL traffic• iSightSpy: Capture a single frame from the iSight camera• <strong>Mac</strong>hiavelli: Remotely control a compromised system throughremote <strong>Mac</strong>h IPC• Uncloak: Identify and dump kernel modules that have removedthemselves from the kmod linked list.References1. Apple, kextstat, http://www.opensource.apple.com/source/kext tools/kext tools-117.4/kextstat main.c.2. Joseph Boykin, David Kirschen, Alan Langerman, and Susan LoVerso, Programmingunder mach, Addison-Wesley Professional, 1993.3. Dino A. Dai Zovi, Trail of bits, http://trailofbits.com/.4. Joseph Kong, Designing bsd rootkits, No Starch Press, 2007.5. Charlie Miller and Dino A. Dai Zovi, The mac hacker’s handbook, Wiley, 2009.6. nemo, Weaponx, http://packetstormsecurity.org/UNIX/penetration/rootkits/wX.tar.gz.7. Amit Singh, <strong>Mac</strong> os x internals, Addison-Wesley Professional, 2006.8. wowie and ghalen, Developing mac osx kernel rootkits, Phrack 13 (2009), no. 66,16.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!