Tuesday, April 23, 2013

Hunting D-Trace Rootkits with The Volatility Framework


I recently attended InfiltrateCon 2013 and got to see the latest and greatest offensive security issues. There was a presentation by Nemo titled 'Destructive D-Trace - With Great Power Comes Great Responsibility' that caught my attention. In his talk Nemo showed examples on how to use D-Trace on OS X to hide an attacker's presence and claimed that forensics techniques would have a hard time detecting these. That claim made me think about the Volatility Framework's latest support for Mac OS X memory analysis and its capability to detect the presence of D-Trace cloaking.

Destructive D-Trace and Rootkits

D-Trace is generally considered a dynamic tracing framework that is used for troubleshooting system issues in real time. While the idea of using D-Trace to perform reverse engineering and detect rootkits has been around for a while [pdf],  it has not been used as a rootkit development platform to my knowledge. In his presentation, Nemo presented techniques to hide files from ls/lsof/finder, hide processes from the Activity Monitor/ps/top, capture private keys from ssh sessions, and inject javascript to HTML pages as they are rendered by Apache. To realize these techniques he utilized D-Trace's 'destructive actions', such as copyout. 

The Volatility Framework on OS X

The Volatility Framework included OS X support in its main body of code back in October 2012. Since then there has been a steady flow of plugins for the OS X platform. Using the Volatility Framework's plugins you can get a list of running or dead processes, get mounted devices, detect rootkits and more. A typical command to get a list of processes looks like:

$ python vol.py mac_pslist -f ~/memory_samples/ram_dump.mach-o --profile=MacLion_10_7_4_AMDx64

Memory Profiles

One of following can be used as a --profile option depending on the analyzed system:

MacLeopard_10_5_3_Intel MacLeopard_10_5_4_Intelx86 MacLeopard_10_5_5_Intelx86 MacLeopard_10_5_6_Intelx86 MacLeopard_10_5_7_Intelx86 MacLeopard_10_5_8_Intelx86 MacLeopard_10_5_Intelx86 MacLion_10_7_1_AMDx64 MacLion_10_7_1_Intelx86 MacLion_10_7_2_AMDx64 MacLion_10_7_2_Intelx86 MacLion_10_7_3_AMDx64 MacLion_10_7_3_Intelx86 MacLion_10_7_4_AMDx64 MacLion_10_7_4_Intelx86 MacLion_10_7_5_AMDx64 MacLion_10_7_5_Intelx86 MacLion_10_7_AMDx64 MacLion_10_7_Intelx86 MacMountainLion_10_8_1_AMDx64 MacMountainLion_10_8_2_AMDx64 MacMountainLion_10_8_3_AMDx64 MacSnowLeopard_10_6_1_AMDx64 MacSnowLeopard_10_6_1_Intelx86 MacSnowLeopard_10_6_2_AMDx64 MacSnowLeopard_10_6_2_Intelx86 MacSnowLeopard_10_6_4_AMDx64 MacSnowLeopard_10_6_4_Intelx86 MacSnowLeopard_10_6_5_AMDx64 MacSnowLeopard_10_6_5_Intelx86 MacSnowLeopard_10_6_6_AMDx64 MacSnowLeopard_10_6_6_Intelx86 MacSnowLeopard_10_6_7_AMDx64 MacSnowLeopard_10_6_7_Intelx86 MacSnowLeopard_10_6_8_AMDx64 MacSnowLeopard_10_6_8_Intelx86 MacSnowLeopard_10_6_AMDx64

If you are not sure what profile to use, you can save the above table's content in a file (e.g. macprofiles.txt) and brute force with the following command till you get a valid output:

awk '{print("python vol.py mac_tasks -f ram_dump.mach-o --profile="$0);system("python vol.py mac_tasks -f ram_dump.mach-o --profile="$0)}' macprofiles.txt

OS X Plugins for Detecting Rootkits

mac_check_syscalls  Checks to see if system call table entries are hooked
mac_check_sysctl  Checks for unknown sysctl handlers
mac_check_trap_table  Checks to see if system call table entries are hooked
mac_trustedbsd  Lists malicious TrustedBSD policies
mac_notifiers  Detects rootkits that add hooks into I/O Kit (e.g. LogKext)
mac_ip_filters  Reports any hooked IP filters

Simple D-Trace Rootkit

I'll only be showing one example that's based on Nemo's presentation since he mentioned that he had a book coming out this summer that talks about OS X Rootkits and I don't want to ruin the fun for him. The example I'll show is a simple D-Trace rootkit that can hide a folder from the command ls. It uses syscall probes to hook the getdirentries64 function and rewrites the function's return values to hide the target folder. You can find the script at github.com/siliconblade/dtrace. To run the script in destructive mode you'll have to use the following command:

sudo dtrace -w -s dirhide.d

Once running, the script will hide the third entry in the /private/tmp folder.

Before running the script (ls -la /private/tmp, we will be hiding the third entry, .badness):

Running the script:

During script execution .badness is no longer visible  (ls -la /private/tmp):

Collecting Memory Samples

To detect the changes introduced by D-Trace, you'll need to collect memory samples before and during running the script. This can be achieved by using the Mac Memory Reader. As suggested at the tool's web site you can use the following command to save the memory sample on a FAT formatted drive:

sudo ./MacMemoryReader - | split -b 2048m - ram_dump.mach-o.

Analysis of the Samples

Since we know that the D-Trace script used syscall probes to hook the getdirentries64 function, we will use the Volatility Framework's mac_check_syscalls plugin to check for the hooks' presence. Using the plugin mac_check_syscalls on the memory sample with the hooked function will not yield an entry with the 'HOOKED' label as intended by the plugin. This is due to the fact that the plugin checks to see if a syscall's address is within the known symbol addresses and a D-Trace syscall is in the list of known addresses. For that reason we captured before and after samples to monitor the changes in the system. The following commands were executed on the before and after samples:

$ python vol.py mac_check_syscalls -f ~/memory_samples/ram_dump-before.mach-o --profile=MacLion_10_7_4_AMDx64 > before_syscalls.txt

$ python vol.py mac_check_syscalls -f ~/memory_samples/ram_dump-after.mach-o --profile=MacLion_10_7_4_AMDx64 > after_syscalls.txt

To view the difference between the two output files:

$ diff before_syscalls.txt after_syscalls.txt
< SyscallTable       344 0xffffff8000306b20 _getdirentries64              
> SyscallTable       344 0xffffff80005c89e0 _dtrace_systrace_syscall 

The diff output shows that the getdirentries64 syscall entry in row #344, was replaced with a D-Trace syscall. 


The D-Trace rootkit's activities are visible and detectable after all! Instead of collecting before and after samples, we could have spotted the D-Trace syscall in the hooked sample, which would have warranted further digging. Nemo's presentation has shown again that known tools can be used for subverting a system and won't be easy to spot by a novice investigator, but then again nothing can hide in memory ;) [The follow up to this post where I talk about detecting more D-Trace providers with a Volatility plugin is here.]

No comments:

Post a Comment