• Objective See
  • about
  • blog
  • malware
  • products

Objective-See's Blog

Monitoring Process Creation via the Kernel (Part II)
11/22/2015

Last week, in (part I) of this blog mini-series, I discussed why BlockBlock required processes creation notifications, and one way to achieve this via a kext. Specifically, the blog post showed a MAC policy could be registered that would receive notification whenever a process was started.

Once I posted the blog, the venerable @osxreverser and others (mahalo Simon!), were kind enough to reach out to me to mention that such process monitoring could equally be achieved via the Kernel Authorization (KAuth) subsystem. As the KAuth interface is a more stable API than the MAC framework (which is 'unsupported' by Apple), I decided to explore this option.

continue reading »


Monitoring Process Creation via the Kernel (Part I)
11/15/2015
Update: Several people have reached out to me (mahalo!) to mention that the KAuth API can also be used to monitor process creation from a kext. While I wait for a kext signing certificate from Apple I'll going to check this out, as KAuth interface appears more stable than the prototype of the MAC policy function. Findings will be included in part II of this blog posting :)

Having recently returned from presenting at VirusBulletin and EkoParty, I finally have some free time to catchup on my todo list. First up? - updating BlockBlock for El Capitan compatibility. Although most of BlockBlock's code and logic works great on El Capitan, one component is completely broken...thanks to Apple's changes to their latest OS.

Background
BlockBlock monitors file I/O events in order to detect "persistence attempts." When it detects such an event, it alerts the user. In order to provide an informative alert, the alert popup contains the pid, path, and ancestry of the process responsible for at attempted persistence:



Although an application could use the FSEvents API to be alerted of specific file and directory changes, this API does not provide information about the process that generated the event. That is to say, sure you get notifications from the API such as, "hey, a new launch daemon (plist) was created" - but there is no direct or trivial way to then get the pid and/or path of the process that created the new daemon.

As such BlockBlock utilizes the /dev/fsevents device directly, as suggested by Amit Singh in his seminal "OS X Internals" book. While this mechanism captures all file I/O (as opposed to only events of interest), it does provide the process id (pid) of the process that generated the file I/O event. Now this is a good start, but as previously mentioned, BlockBlock seeks to provide the user more information about the responsible process such that the user may make an educated decision. For example, being able to display the process's path and process ancestry is definitely useful (if not essential), information that should be contained in a BlockBlock alert.

Generally, given a pid, one can simply call API functions such as proc_pidpath (see libproc.c) to get a process's path. However, if the process is short-lived and has already exited, this (and other) APIs will fail. As such, BlockBlock separately keeps a list of all process creations that includes somewhat detailed information about each process such as its pid and full path. Then, when a "persistence attempt" is detected via the file I/O monitoring component, even if the process has exited, BlockBlock can use the pid that's tied to the file I/O event to query its process list to get required information, such as the process's path.

Prior to El Capitan, BlockBlock used programmatic dtrace probes in order to record process creation events. Specifically it set probes from user-mode, on:
1. syscall::exec*:return
2. proc::posix_spawn:exec-success
3. syscall::fork:return

These probes allowed not only pids, but also process paths, uids, and ppids to be recorded by BlockBlock. All was well :)

Then along came El Capitan - and basically said, "no more (meaningful) dtrace" Don't believe me? Try running Apple's very own exesnoop that ships with the OS. As it uses dtrace, it's totally broken, even when run as root :(


When I reached out to Apple about this I was told: "[you] can't trace syscalls using dtrace when SIP is enabled. We [Apple] can't make the distinction between a path or something more private."

It should be noted that yes, one can still do basic dtracing of some processes. However, there appears to be no (legitimate) way of tracking process creation events via dtrace, in a way that also provided semi-detailed information about the process, such as its full path. As BlockBlock requires (or I should say, prefers) such detailed information I had to explore other approaches.

First, thanks to suggestion from @hey_pom, I dove into the audit (open BSM) framework. While this isn't that well documented, I was able to coerce some user-mode code to cough up some semi-detailed information for each process creation. Unfortunately, this information varied based on how the process was created (execv'd, forked, or spawned). For example; when a process is forked, the audit subsystem only provides the pid (no path), while for a spawned process, only the process's path is provided:


This is less than ideal, as BlockBlock requires a comprehensive pid -> process path mapping (even for short-lived/terminated processes). With all user-mode options (to the best of my knowledge) exhausted, I decided to head into ring-0.

Ring-0/Kext
Again, my goal was simple; record all process creation events so that at a later time, both the process id and full path of the newly created process would (still be) accessible. After a bunch of googling, it seemed that the simplest way to monitor process creations in ring-0 was via a mandatory access control (MAC) policy. Although this is (still?) an unsupported KPI, we'll see it provides the perfect solution to our issue. That is to say; it provides a comprehensive way to monitor process creations in a detailed manner.

The mandatory access control implementation for OS X is TrustedBSD. For a quick primer and solid overview, checkout "Working with TrustedBSD in Mac OS X." In terms of using a MAC policy to monitor process creations, I recalled one of @osxreverser's blog post titled "Can I SUID: a TrustedBSD policy module to control suid binaries execution". In this posting he discussed how one might control the execution of suid binary execution via a MAC policy. The code he shared is easy to follow and shows exactly how to register, via a MAC policy, a function that will be automatically called by the OS anytime process is created. Though he uses this policy function to determine if the process's binary has any SUID bit set, we can tweak the code so that the function can also access process id, path, parent id, and uid. Perfect - that's all we need :)

Let's now walk thru some ring-0 code that implements such a MAC policy/hook (note, we'll cover how to make this information available to BlockBlock's user-mode components in part II of this blog post). If you'd like to follow along in code, its downloadable as an Xcode project. Again, mahalo to @osxreverser - this code is fully inspired by his previous work!

Kernel extensions (or 'kexts') are the legitimately way introduce code into the kernel. There are two kinds of kexts; 'Generic Kernel Extensions' and 'IOKit Drivers':


Since I wanted BlockBlock to be installable without requiring a reboot, I went with the former. (Apple answered when asked if it is possible to install an I/O Kit kext without requiring a restart: "There is no easy solution to this problem. Currently, even Apple's own installers require restarting after a kext installation.")

Conceptually, in order to record detailed information of all process creations, our generic kext only has to do two things. First, register a MAC policy (indicating our desire to monitor process creations). Then, implement the MAC policy function that is automatically invoked by the OS whenever a process is started. Within this function, we can add code to record details about the process (pid, path, ppid, etc).

Step 1: Registering the MAC Policy
In the kext's start function, (specified in kext's build settings, under 'Module Start Routine'), invoke the mac_policy_register function. As shown below, this function takes three parameters; a pointer to the MAC policy configuration, an (out) pointer to the MAC policy handle, and the second argument that was passed to the kext's entry point function.


The following code snippet, illustratess the invocation of this function:
kern_return_t BlockBlockKext_start(kmod_info_t * ki, void *d)
{
   ...

   //register MAC policy
   mac_policy_register(&policyConf, &policyHandle, d);

   ...
}

Let's take a closer look at the first two parameters of the mac_policy_register function. As just mentioned, the first parameter is a pointer to a MAC policy configuration. Specifically this is pointer to a structure of type mac_policy_conf. Defined in security/mac_policy.h this structure is defined as follows:
//defined in security/mac_policy.h
struct mac_policy_conf
{
   const char *mpc_name;
   const char *mpc_fullname;
   const char **mpc_labelnames;
   unsigned int mpc_labelname_count;
   struct mac_policy_ops *mpc_ops;
   int mpc_loadtime_flags;
   int *mpc_field_off;
   int mpc_runtime_flags;
   mpc_t mpc_list;
   void *mpc_data;
};


Although somewhat complex, luckily most the members in this structure can be initialized to blank or NULL values. However, four should (must?) be set.

1) const char *mpc_name
This is the policy name. You can pick any string ("BB Process Monitor")

2) const char *mpc_fullname
This is the policies full name. Again, pick any string ("BlockBLock Kernel-Mode Process Monitor")

3) struct mac_policy_ops *mpc_ops;
This is the most important member of the mac_policy_con structure. Described by Apple, as an 'operations vector' it should contain a pointer to a mac_policy_ops structure. The mac_policy_ops structure specifies what operation (e.g. 'process creation') the kext is interested in, and the name of the callback function to invoke when said operation or event occurs. This details of the mac_policy_ops structure are discussed in more detail below.

4) int mpc_loadtime_flags
These flags indicate such things as whether the policy (and thus kext) can be unloaded ('MPC_LOADTIME_FLAG_UNLOADOK') or when the policy should be loaded.

The following shows the fully populated mac_policy_con structure, used in BlockBlock's kext:
//MAC policy
// ->pretty much empty, save for name and pointer to ops vector

static struct mac_policy_conf policyConf =
{
   .mpc_name = "BB Process Monitor",
   .mpc_fullname = "BlockBLock Kernel-Mode Process Monitor",
   .mpc_labelnames = NULL,
   .mpc_labelname_count = 0,
   .mpc_ops = &bbPolicyOps,
   .mpc_loadtime_flags = MPC_LOADTIME_FLAG_UNLOADOK,
   .mpc_field_off = NULL,
   .mpc_runtime_flags = 0,
   .mpc_list = NULL,
   .mpc_data = NULL
};

As mentioned (step #3), the mac_policy_ops structure tells the OS what policy or event one is interested in. In order to register for process creation notifications, specify the mpo_vnode_check_exec_t MAC policy operation and provide a callback policy function:
//policy ops
// ->specific MAC hooks

static struct mac_policy_ops bbPolicyOps =
{
   //only interested in exec
   // ->blockblock's policy function

   .mpo_vnode_check_exec = processExec
};


Step 2: Implementing the MAC Policy Function
Once registered, the policy function (here, named 'processExec') will be automatically invoked by the OS anytime a process is being created.

The prototype of the policy function is rather long, and unfortunately, as @osxreverser notes, sometimes changes between OSs. However, since Yosemite it has remained the same. (As such this kext will only run on versions of OS X Yosemite and newer):
static int [functionName] (kauth_cred_t cred, struct vnode *vp, struct vnode *scriptvp, struct label *vnodelabel,struct label *scriptlabel, struct label *execlabel, struct componentname *cnp, u_int *csflags, void *macpolicyattr, size_t macpolicyattrlen);

Luckily, in order to access detailed information about the process being created, only the first vnode parameter (vp) is needed. All other parameters for the purpose of this project, can be ignored. Recall, BlockBlock requires the pid, ppid, uid, and process path, for all created process. Turns out, all this information is readily available within the mpo_vnode_check_exec's policy function (here, named processExec):

1) pid
The process's id, can be accessed via a call to the proc_selfpid() function

2) ppid
The process's parent id, can be accessed via a call to the proc_selfppid() function

3) uid
The process's user identifier can be accessed via a call to the kauth_getuid() function

4) path
The passed in vnode argument pointer ('vp') can be used to get the process's full path. Simply invoke the vn_getpath() function, passing in the vnode parameter and an out buffer, and pointer to the out buffer's size:
//path
char path[MAXPATHLEN] = {0};

//length
int pathLength = MAXPATHLEN;

//get process path
vn_getpath(vp, path, &pathLength);

Performing steps 1 thru 4 in the MAC policy function (which we named processExec), allows the BlockBlock kext to retrieve all required information about process creations:
//MAC policy function for mpo_vnode_check_exec
// ->automatically invoked anytime a new process is started

static int processExec(kauth_cred_t cred, struct vnode *vp, struct vnode *scriptvp, struct label *vnodelabel,struct label *scriptlabel, struct label *execlabel, struct componentname *cnp, u_int *csflags, void *macpolicyattr, size_t macpolicyattrlen)
{
   //path
   char path[MAXPATHLEN] = {0};

   //length
   int pathLength = MAXPATHLEN;

   //uid
   uid_t uid = -1;

   //pid
   pid_t pid = -1;

   //ppid
   pid_t ppid = -1;

   //dbg msg
   printf("BLOCKBLOCK KEXT: MAC policy hook invoked\n");

   //get path
   vn_getpath(vp, path, &pathLength);

   //null-terminate
   // ->just to be safe

   path[MAXPATHLEN-1] = 0x0;

   //get UID
   uid = kauth_getuid();

   //get pid
   pid = proc_selfpid();

   //get ppid
   ppid = proc_selfppid();

   //dbg msg
   printf("BLOCKBLOCK KEXT: %s %d/%d/%d\n", path, pid, ppid, uid);

   //TODO: part II, send to user-mode!
   ...
}


Go Time
Time to test this out! Since this is a beta kext, I'd suggest testing it in a VM. Once the kext is compiled (simply open in Xcode and hit Project->Build) and copied to the VM, change its owner to root/wheel:
$ sudo chown -R root:wheel BlockBlockKext.kext

Since OS X no longer (legitimately) allows the loading of unsigned kernel extensions by default, the VM must be explicitly configured to disable this 'security' feature. For Yosemite, tell the OS to allow the loading of unsigned kernel extensions via:
$ sudo nvram boot-args=kext-dev-mode=1
$ sudo reboot

On El Capitan accomplish the same via:
a) boot into recovery mode via cmd+r
b) csrutil disable (from Terminal.app)
c) reboot

Now, load the kext:
$ sudo kextload BlockBlockKext.kext

If all goes well the kext should be loaded (I've tested it on Yosemite, and El Capitan). Open Console.app to monitor the kext's output. Try launch some apps, or execute some processes:


Obviously for production code, one would want to sign the kernel extension so users can install BlockBlock without having to turn off kext-signing checks. According to online documentation a normal Apple Developer ID is not longer enough to sign a kernel extension. Instead, one must request a 'Developer ID for Signing Kexts' via this form. Seems easy enough assuming one is developing legitimate OS X software? Or so I though:

Me: "Aloha, Objective-See LLC would like a Developer ID for Signing Kext, so that it may sign its kernel extensions for it customers. This is for a legitimate software product that does not attempt to bypass OS X security features in any way"

(note: I also provided the technical reasoning why BlockBlock (now) required a kext, as well as a link to BlockBlock's product page)

Apple: GTFO:


Me: ...

On that bitter(sweet) note, let's end. Check back soon for part II (and maybe Apple will have reconsidered their decision to deny me the ability to sign kexts). I'll detail about how the process information captured in the BlockBlock kext, is made available to the user-mode component of BlockBlock via broadcasting to a system socket :)


Kernel Debugging a Virtualized OS X El Capitan Image
11/05/2015
Invariably, any serious security researcher or hacker will at some point, need to debug a live kernel. Recently I found some interesting code within a kernel extension that I wanted to poke on...dynamically. My previous kernel debugging experience involved GDB, and older versions of OS X. Setting up kernel debugging against an OS X 10.11 image with LLDB, was thus a new experience. As such, I figured a short blog detailing the necessary steps, perhaps would be useful to others :)

Host: My host is running OS X 10.11.1, however any recent version of OS X should work similarly.
I've also got XCode and VMWare Fusion installed.

Target: My target is a virtual instance of the release build of OS X 10.11 (running within VMWare).
This is what we'll be remotely debugging.

So how can we kernel-debug an OS X 10.11 image running release kernel, in a VM. Turns out, it's really not too hard!

Step 1 (target): Disable System Integrity Protection (SIP)
Boot the target (VM) into recovery mode. This is accomplished by hitting cmd+r as the system boots. Note; if the target boots to a login prompt, you've missed recovery mode. Reboot and try again.



Once in recovery mode, open the terminal (Utilities ->Terminal) and enter the following: csrutil disable


This will disable system integrity protection. Reboot the target, allowing it to boot normally.

Step 2 (target): Enable Debugging
Once SIP has been disabled, and the target has booted normally, you need to tell the system to boot in 'debug-mode'. This is achieved via the following command, executed from the terminal, within the target:
sudo nvram boot-args="debug=0x141 pmuflags=1 -v"

The 'debug=0x141' tells the system to wait for a remote debugger while booting. While the 'pmuflags=1' disables the kernel's watchdog timer. Finally -v just tells the kernel to boot in verbose mode. For more information on these parameters, see Kernel debugging with LLDB and VMware Fusion or Apple's Kernel Programming Guide.

Reboot the target, it should begin booting, then pause waiting for a remote debugger to attach:



Step 3 (host): Download the Kernel Debug Kit
Head over to Apple's developer page and find the kernel debug kit that matches the target's kernel. Since the target, (the image we're debugging) is the final version of OS X 10.11 (i.e. non-beta), the correct kernel build is 15A284:


Download this dmg, and install it.

Step 4 (host): Start LLDB and Configure
From a terminal, fire up lldb. Then, specify the target you'll be connecting to. Do this via the 'target create [path to target kernel]' command:


Note that the path to the kernel, is the path to the release kernel in the kernel debug kit (downloaded in the previous step).

Once the target has been specified, a warning message is displayed, indicating the presence of a debug script. Run this script via the specified command ('command script import ...):



Step 5: (host) Connect to the Target
Now, you are ready to connect to the remote target, via kdp (the kernel debugging protocol). Connect via the following command: 'kdp-remote [target IP addr]. Note the target's IP address will be displayed by the target, in the line above the 'Waiting for remote debugger connection'. Now the host should be connected to the target!





Step 6: Debug!
Hooray, now connected to the remote target, you and can debug to your heart's content, for example dumping a backtrace or listing the loaded kexts:





One important note, is that (with this setup), the debugger, cannot stop the running kernel - unless a breakpoint is hit! This means, if you don't set a breakpoint before continuing, you won't be able to stop (and thus debug) the running kernel:



There may be ways around this 'limitation.' For example, Kernel debugging with LLDB and VMware Fusion talks about Non-Maskable Interrupts (NMI), that in theory allow one to manually generate an interrupt in the target (at anytime), that will be caught (and thus stop) the debugger on the host. However, I could not get this working...

Well that's a wrap. Hopefully I've adequately described the steps needed to debug the kernel of a virtualized OS X El Capitan image. If you have any issues, or if I've missed a step(s) please shoot me an email :) Happy bug hunting!


Reversing to Engineer: Learning to 'Secure' XPC from a Patch
8/29/2015
Update: blog post updated to describe the use of dynamic (versus static) code references/APIs. Though Apple SPI'd (System Private Interfaced), as pointed out by Damien Sorresso of Apple, these APIs provide a higher level of security, and thus should be used. Mahalo Damien :)

As backwards as it may seem, my (limited) software engineering knowledge has largely come from reverse-engineering other people's software. For example, reversing OS binaries while hunting for vulnerabilities has provided insight into how 'real' software developers think, code, and approach problems. In this brief writeup I want to share such an experience; where knowledge gleaned from a reversing session turned out to be directly applicable to one of my own projects.

At DefCon, I gave a talk entitled, "Stick that in your (root)Pipe and Smoke it" (photo credit, @Ryanwsmith13):


The talk began with a brief overview an OS X IPC mechanism named XPC, before diving into an analysis of an XPC-related vulnerability name 'RootPipe' (discovered by Emil Kvarnhammar). Following this, the talk analyzed Apple attempt at a patch, and illustrated how both I and others were able to bypass the patch and re-exploit the initial vulnerability. While researching content for the talk and reversing Apple's patch, I learned a lot about XPC and how to secure privileged XPC services. This knowledge turned out to be directly applicable to my latest tool; TaskExplorer.


TaskExplorer allows one to explore all the tasks (processes) running on a Mac. IMHO, it provides a much needed improvement over Apple's Activity Monitor, as it allows one to view a task's loaded dylibs, open files, network connections, signature/signing status, and VirusTotal detection ratio. Moreover, a global search feature provides a way to quickly find all tasks that contain a loaded dylib or file. In order to enumerate information about running tasks, such as loaded dylibs and command-line arguments, root privileges are required. Sure TaskExplorer could ask for credentials each time it is launched, but there is a better way: XPC.

As detailed in my talk (and shown in the following figure), XPC is great for splitting up an application into various 'logically-separate' components.


Besides achieving stability, this provides a great way to separate logic that requires different (e.g. elevated) privileges. (For more on XPC, see Apple's "Creating XPC Services" or Damien Sorresso's presentation "Efficient Design with XPC"). TaskExplorer was architected to utilize XPC to achieve such separation; splitting out a privileged XPC component from the application's main UI interface. The privileged XPC component is authenticated the initial time TaskExplorer is launched. From then on, it is able to service requests from the UI component in order to provide required information about remote tasks, without the need for further authentication.


Ok, so back to the DefCon talk and 'RootPipe'. The bug discovered by Emil was both simple and elegant. In short, OS X contained a privileged XPC service (WriteConfig) that applications could communicate with in order to perform privileged actions without constantly bugging the user for credentials. Unfortunately, this XPC service performed no authentication on any clients that connected to it. As such, any local adversary could abuse its services to elevate their privileges to root!


Though TaskExplorer's privileged XPC component does not confer such powerful capabilities, none-the-less I wanted to secure it by only allowing authorized clients to connect. But how?

By reversing Apple's patch, we can see that 'RootPipe' was patched, (after two attempts!), by only allowing authorized clients to connect to the all powerful WriteConfig XPC service. Specifically only Apple-signed binaries with special entitlements, (e.g com.apple.private.admin.writeconfig), are able to connect to the XPC service.


Where is this new logic, that either allows trusted or blocks untrusted clients, implemented? In WriteConfig's implementation of the -listener:shouldAcceptNewConnection: method. Apple's documentation states that this delegate method can be used to "accepts or rejects a new connection to the listener." In other words, the XPC service can examine a candidate client and block or reject the client, if it so chooses. Apple's 'RootPipe' patch and now TaskExplorer, both utilize this delegate method in order to validate candidate clients.

Apple's documentation states that this NSXPCListenerDelegate delegate method can be used to "accepts or rejects a new connection to the listener." In other words, the XPC service can examine a candidate client and block or reject the client, if it so chooses. Apple's 'RootPipe' patch and now TaskExplorer, both utilize this delegate method in order to validate candidate clients.

Instead of using entitlements to validate candidate clients connecting to TaskExplorer's XPC service, I choose a simpler route: only applications signed by Objective-See are allowed to connect, and thus utilize the XPC service. Unfortunately, there's not a lot of documentation or examples about how to verify if an candidate client is signed with a specific Apple Developer's ID. However, a few StackOverflow posts, code snippets on GitHub, and fully reversing Apple's patch, initially proved quite helpful. Of course a little coaching from Damien Sorresso (@launchz) was amazingly helpful as well ;)


As with Apple's 'RootPipe' patch, code within TaskExplorer's -listener:shouldAcceptNewConnection: method, first invokes the SecTaskCreateWithAuditToken() function. Though undocumented, the definition and a brief overview can be found in the SecTask.h header file. As explained in the header file, this function "create[s] a SecTask object for the task that sent the mach message represented by the audit token." In other words, given an audit token of the client task that is attempting to connect to the XPC service, it will return a SecTask object representing said client. As described shortly, such an object will allow us to fully validate the client. So how to get the audit token of the connecting client to pass to the SecTaskCreateWithAuditToken() function?

Well, as can be seen in the disassembly of Apple's patch, it appears that the shouldAcceptNewConnection: parameter, a pointer to an NSXPCConnection object, has method named 'auditToken', which presumable return's the connection's (client's) audit token:


Unfortunately, the is no mention of such a method in any Apple documentation or header files. However using a tool such as RuntimeBrowser we can view NSXPCConnection's full class. This confirms the presence of such a method:


Since this method is not 'public', one has to gently coerce the Objective-C runtime to give us access to it. One easy method is simply to create an custom class that contains an instance variable and '@synthesize' of the same name ('auditToken'). Then the following code will return, executed upon the NSXPCConnection object, will return the client's audit token: ((ExtendedNSXPCConnection*)newConnection).auditToken. With the ability to access the client's audit token, we can invoke the SecTaskCreateWithAuditToken() function and get back the needed SecTask object, and then validate the client.

Within the SecTaskPriv.h header file, exists a function named SecTaskValidateForRequirement(). A comment above the function states that it will "validate a SecTask instance for a specified requirement" - sounds perfect! Besides taking a reference to a SecTask object (which we now have), this function takes a 'requirement' string. Such a string articulates the desired requirement that can be validated against the connecting client, for example: "client; you must be signed with Objective-See's Apple Developer ID". The following format string illustrates the format of such a requirement, that can be passed into the SecTaskValidateForRequirement() function to validate a connecting client.

@"anchor trusted and certificate leaf [subject.CN] = \"Developer ID Application: your Apple Developer ID\"";

By the way, to find the correct string for your Apple Developer ID, run the codesign tool with the '-dvv' flags. Use the text following the first 'Authority=' as the requirement string (e.g. "Developer ID Application: Objective-See, LLC (VBG97UB4TA)").



To summarize, the following steps can validate that a client, connecting to an XPC instance, is signed by a particular Apple Developer ID. This code should be placed within the XPC service's -listener:shouldAcceptNewConnection: method.

0) Declare a custom class that 'extends' the NSXPCConnection object, allowing access to it's 'private' auditToken. While there are likely other ways to accomplish the following seems to work :)

@interface ExtendedNSXPCConnection : NSXPCConnection
{
   audit_token_t auditToken;
}
@property audit_token_t auditToken;
@end

@implementation ExtendedNSXPCConnection

   @synthesize auditToken;

@end


1) Invoke the SecTaskCreateWithAuditToken() function with the client's audit token to create a SecTask object for the connecting client.

2) Invoke the SecTaskValidateForRequirement() function, passing in the SecTask object and a requirement string for validation. To validate that the client is signed with a particular Apple Developer ID, use the following string (of course inserting your Apple Developer ID) :@"anchor trusted and certificate leaf [subject.CN] = \"Developer ID Application: your Apple Developer ID\"";

Putting these steps together, here's a snippet of code from TaskExplorer that attempts to ensure that only authorized clients can connect to its privileged XPC service. And yes, it uses 'goto' - deal with it ;)


Often, the primary goal of reverse-engineering is to find vulnerabilities, understand malware, or validate vendor patches. However, if you're an amateur software developer, reversing can provide the means to improve ones very own tools. So, mahalo Apple!


Building HackingTeam's OS X Implant For Fun & Profit
7/12/2015
By now, it's old news that HackingTeam got hacked. The collective info-sec community has being pouring thru the 400GB haul of 0days, juicy emails, and source code. Here, we add to this chorus by discussing how to build HackingTeam's persistent OS X implant from source - as what's cooler than being able to step thru malware's source code in Xcode?

The HackingTeam's OS X implant, 'Crisis' has been previously seen in the wild and analyzed. However, thanks to the leak, full source code is now available! Having access to malware's source code alone, can provide unparalleled insight and reveal its innermost secrets. However, being able to fully build and thus dynamically debug said source code, can greatly simplify and expedite this analysis. Therefore this was goal: get HackingTeam's OS X implant to compile, in order to be debuggable under Xcode, on a modern version of OS X.

Ok, let's dive in! Within the /core-macos-master/core/ directory is the Xcode project of the malware's core; RCSMac.xcodeproj. This is the project that compiles various components of the malware, such as its installer and local 'server' components.



Opening this file in Xcode results in various popups asking to modernize the project. Agreeing to these allows Xcode to attempt various project 'modernizations' such as updating the SDK configuration and converting the project to make use of ARC (garbage collection).



Unfortunately, despite Xcode's best efforts various issues remain, preventing compilation. First, as the project's compiler is unsupported, this has to be updated to the current default compiler (Apple LLVM 6.1):



Then, since recent versions of Xcode prefer to compile only for 64-bit (x86_64) platforms, all references to 32-bit architectures (i386) have to be removed.



After this, various ARC-related issues that Xcode could not automatically fix, have to be manually addressed:



For example, code related to auto-release pools, retain, and release must be removed.



Finally after these various manual fixes, the code compiles...but alas, does not link :( This is due to fact the included copy of a required library, speex, was not built for 64-bit:



To build a 64-bit compatible version of the library, simply download the speex library source code and build it (./configure; make; etc). Once built, the library, libspeex.a, should be copied into the malware's project (/core-macos-master/core/Support/Speex/libspeex.a), overwriting the existing 32-bit version.

Horray, everything now (finally) compiles and links!



Once the HackingTeam's malware has been build, it should be trivial to analyze by debugging it in Xcode. However, the compiled malware still has various features that may complicate this process. For example it contains amongst other things, anti-debugging code. Luckily, this and various other features can be controlled by several #defines found within RCSMDebug.h header file. Though commented out, simply uncommenting them and re-compiling disables all anti-debugging, as well as enables other useful features such as logging and placing the malware into 'demo' mode:



With a cleanly built, debug version of the implant, debugging and analysis can commence:



While a full analysis of the code is beyond the scope of this blog entry (but should be fairly easy for anybody with Xcode to perform), let's end with discussing the malware's persistence mechanism. Looking at the runMeh method (within RCSMCore.m), reveals the malware persistently installing itself via a call to the makeBackdoorResident method.



This method eventually calls into the saveSLIPlist method, which is responsible for persisting the implant as a LaunchAgent, via ~/Library/LaunchAgents/com.apple.loginStoreagent.plist:



Since LaunchAgent persistence is detected by BlockBlock, if the HackingTeam had targeted your Mac and you had BlockBlock installed, it's unlikely they'd have succeeded in infecting you. Booya!



Update: an anonymous individual has uploaded a ready-to-go 'Xcode-buildable' version of the implant. Download it, build it, and play :)


CVE-2015-3673: Goodbye Rootpipe...(for now?)
7/01/2015
In a previous blog post, I posted a video showing a modified version of 'rootpipe' (the priv-esc disclosed by Emil Kvarnhammar), bypassing Apple's patch to successfully (re)gain root on OS X 10.10.3. The bug, which I reported to Apple, was assigned CVE-2015-3673 and patched in OS X 10.10.4:



Interesting, though not that surprisingly, Emil found the same way to bypass Apple's original patch. As such, we share the CVE :)

With the release of OS X 10.10.4 and Apple's new patch, Emil wrote a great blog revealing the details our independent OS X 10.10.3 bypass. In short, Apple's original patch allowed only trusted processes (specifically those with the com.apple.private.admin.writeconfig entitlement), to talk to the WriteConfig XPC service; the service that the original 'rootpipe' exploit abused. However, we both found that the trusted Directory Utility application could easily be coerced to load unsigned, malicious plugins:



Since the Directory Utility application possesses the com.apple.private.admin.writeconfig entitlement, even on a patched OS X 10.10.3 system, the malicious plugins were allowed to talk to the writeConfig XPC service - game over! Apple's most recent patch prevents this attack in variety of ways (such as ensuring the trusted process originates from /System or /usr, both which are of course, only writable by root). As such, (for now?), 'rootpipe' is no more.

If this adventure has interested you, I'm happy to announce that I will be presenting an in-depth talk at DefCon 23. The talk, titled "Stick That In Your (root)Pipe & Smoke It" will cover in great detail: XPC fundamentals, the rootpipe vulnerability, malware (from China?) that exploited the flaw as an 0day, Apple's attempted patch, the bypass (mentioned here), and Apple's OS X 10.10.4 patch. Can't make the talk? No problem; I'll be sure to post the slides online. Here's a sneak preview:



While on the topic of upcoming events, I've also been accepted to BlackHat Las Vegas where I'll be presenting a talk on "Writing Bad @$$ Malware for OS X" :) Also, I'll be giving yet another talk at DefCon 23 titled "'DLL Hijacking' on OS X? #@%& Yeah!". Finally, I was invited to demonstrate Objective-See's tools at BlackHat Arsenal, where I'll be releasing a new tool - so come check it out.

Hopefully see you in Vegas at BlackHat, Arsenal, DefCon - or all three!


More on, "Adware for OS X Distributes Trojans"
6/22/2015
Today, Dr. Web released a brief writeup titled "Adware for OS X Distributes Trojans". Though the writeup provided a decent overview of the malware, it glossed over many technical details. Here, we provide a little more technical depth as well as the malicious sample - in case you want to play along at home! (See the MacInstaller/ folder in Objective-See's malware archive (password: infect3d), for the malware mentioned here).

The Dr. Web writeup mentions an installer that is distributed as adware, specifically "disguised as a useful application or an MP3 file." While the websites that host the malicious installer are not directly mentioned, one of the screen shots contains the URL, listentoyoutube.com. Visiting and interacting with this site (e.g. providing a youtube video or song to download), results in the following 'Download MP3' button:



Observant readers will notice the checked (by default), "Download with accelerator and get recommendation offers" option. With this option checked, clicking the download button will download a .dmg image, named to matched the MP3. When executed, an application within the .dmg is launched which may infect the user, installing several pieces of persistent adware.

The Dr. Web write up mentioned that this image contains a "rather remarkable structure; that is, it contains two hidden folders that cannot be viewed on the computer running with standard operating system settings if the user decides to browse the contents of the DMG file using Finder." This "remarkable structure" IMHO is rather unremarkable, the folders are simple prefixed with a '.' so that Finder will not, by default, display them. However, they are visible if Finder has been instructed to show hidden files, or of course, from the Terminal:



When the .dmg is mounted (e.g. double clicked) the following is shown:



Double-clicking launches the <song>_mp3.app which executes its binary image: 'macLauncher' (MD5: 5f1e998e0213364ae44472495a71f123). This binary simply executes an application named 'Downloader' found within the hidden .app/ folder. Interestingly, this execution is achieved by the programmatic invocation of an AppleScript script:



As its name implies, 'Downloader' is a application that downloads (and installs) other software. Strings within the binary reveal it name, 'macInstaller', and version, 1.7.12-d. The MD5 hash of this binary is a6a23e7815d08a596da37e38b466e7a2.

When executed, this software infects the system with persistent adware. Analysis of this adware is beyond the scope of this writeup. However, brief triage indicated that this includes a (signed) variant of Genieo, as well as the abhorred 'SaveOnMac' or (Crossrider?) adware.

This adware will result in variety of unwanted or malicious behavior. For example, via malicious browser extensions it will hijack the browser in various ways. These malicious extensions can be viewed with KnockKnock:



Genieo, goes a step further and attempts to persist as a LaunchAgent. Luckily, BlockBlock can block this:



Since this version of Genieo was unknown to VirusTotal and (when submitted), undetected by Dr. Web and other AV products, a malware-agnostic tools such as BlockBlock is clearly quite valuable ;)




Phoenix: RootPipe lives! ...even on OS X 10.10.3
4/18/2015
Recently, a new OS X priv-esc vulnerability named 'rootpipe' was disclosed. Apple attempted to patch the vulnerability in OS X 10.10.3, by adding access checks via a new private entitlement: com.apple.private.admin.writeconfig. (see @osxreverser's excellent writeup for details). In theory this seemed a reasonable fix.

However, on my flight back from presenting at Infiltrate (amazing conference btw), I found a novel, yet trivial way for any local user to re-abuse rootpipe - even on a fully patched OS X 10.10.3 system. I the spirit of responsible disclosure, (at this time), I won't be providing the technical details of the attack (besides of course to Apple). However, I felt that in the meantime, OS X users should be aware of the risk.


Phoenix (rootpipe reborn) demo on OS X 10.10.3



Dylib Hijack Scanner Released
3/19/2015
Objective-See's first tool, 'Dylib Hijack Scanner' (DHS) has been released! This product attempts to counter a new class of OS X attacks, dubbed 'dylib hijacking.' For details on this novel attack, check out my slides or paper.

By abusing weak or run-path dependent imports, found within countless Apple and 3rd party applications, this attack class opens up a myriad attack scenarios to both local and remote attackers. From stealthy local persistence to a Gatekeeper bypass that provides avenues for remote infections, dylib hijacking is likely to become a powerful weapon in the arsenal of OS X attackers. Apple appears apathetic toward to this novel attack, so download DHS to ensure you haven't been hijacked.

I've tried my best to ensure this tool is both accurate and stable, but please email me with any issues you may have.


Website Launch
3/19/2015
And we're (finally) live! Welcome to Objective-See, my personal OS X security website :)

OS X malware and security has been a personal passion for many years. However the more I learned about this topic, the more insecure I felt. Malware for OS X is trivial to write and unfortunately has become ever more pervasive. And, using attacks such as dylib hijacking attackers can easily bypass all current OS X security products.

As an avid Mac user this worried me, so I decided to do something about it. Initially this was for somewhat 'selfish' reasons; I simply wanted to write OS X security tools to secure my Mac. But then I though, "hey, sharing is caring, I should make my tools publicly available, free of charge." This is the idea that drives the website.

So welcome to the website launch. There isn't a lot up here yet, but I promise some cool stuff is coming shortly!



  • © 2015 objective-see llc
  • ✉
  • 
  • 
  • donate!