Moving on with their presentation, the Team T5 experts delve into host privilege on Mac OS X in terms of the scope of permissions that a normal user can get.
A priveleged Normal User
Alright, after hiding files with a rootkit, the next important thing is to give permission to a normal user. I’m going to show you how we silently grant permission to a normal user. Here is a demonstration (see image above). The ‘vm’ parameter actually indicates a normal user. We use ‘kextstat’ to check the kernel module; “nanika.true” – you see it in kernel. We couldn’t find it. And we use our tool ‘kext_load’ to load the kernel module. And you can see, it successfully loaded the kernel module, but it is still normal user. So a normal user can load the kernel module – how do we do this?
It is because of host privilege. With host privilege you can do many things, including load kernel module. You can load kernel module, you can get into kernel – you can do many things. So this privilege is very important. It is similar to root. In the ‘host’ project (see image above) you can see the element storing the host privilege information, and host privileges are listed here. Normal is 1, and special privilege is 2.
With host privilege you can do many things, they are listed here (see image above). At least you can load kernel module. And also, with host privilege you can control kernel tasks (see image below), and I will show you how powerful it is.
Okay, how to obtain host privilege? First, in kernel you have to find ‘_realhost’ from kernel (see image above). You parse kernel and find the symbol. And then, you need to find target task – the task you want to assign the permission, the privilege. And you need to assign this point, ‘_realhost->special’, to task ‘itk_host’. Then this task has privilege, and there is no need to become root as it already has the privilege.
So, how do we implement our rootkit with host privilege? There are several ways, like system call hook and code patching. In the final slide I will show you how we do call patching to make rootkit with this function. So, we try to replace syscall table and then and then we find the address specified, and then we try to patch the code here (see image above). It is global effectiveness: to every user who wants to request permission – the rootkit will grant the permission without asking, without any checking.
This function (see image above) is in charge of checking the host permission of the task. But we modify the code here. Then, the next time this function is called it will always give the permission.
Instead of code patching, which is difficult, we have a better way (see image above). This way is the easiest, undetectable by traditional detection and stable. How do we do this? Very simple (see image below).
We just find the host privilege object and then we specify 2 to 1 so that the normal host privilege is the same as special privilege. We call it “data patch”. If we patch this data, then it has global effectiveness and every user can have permission to load kernel module.
Direct Kernel Task Access
Okay, our normal user can do many things now with host privilege. I am going to show you how and what a normal user can do from user mode and kernel mode. So, the first, direct kernel memory access from user mode. Since Mac OS X 10.6, it restricted task access from kernel task (see image below).
Originally, task_for_pid() can be used to access kernel task, but it is not supported on the kernel task. On the new version of Mac OS X, this function cannot be used to access kernel task. So no matter your privilege level nor what API you use, there is no legitimate use for inspecting kernel memory. But I am going to show you a way, we make it possible again.
For direct task access (see image above) we don’t use task_for_pid(). Instead, we use processor_set_tasks. This API will return a task_list object, and this object is actually the kernel task. So from user mode, you call this function. You need the host privilege at least – and you can call this function. And after you call this function, you can get the kernel task. So, with task_list you can access all tasks from this list. Using this code, we can start to access all tasks and even use vm_read and vm_write to read and write task memory. And also, for example, we can use thread_set_state() for dynamic library injection. So, we make it happen again and we can directly access the kernel task.
Bypass Kernel Module Verification in 10.9
Another thing with host privilege is a normal user can not only load kernel module – we are also going to show you how to bypass kernel module verification on Mac OS X 10.9.
This (see image above) is the standard way of loading kernel module on Mac OS X 10.9. We put the kernel module file – it has to be a file – into the /System/Library/Extensions/ folder, and we run kextload to load the file. If the kernel module not signed, the OS will always pop up a warning message that it is a third-party kernel module.
After we have implemented mykextload, we can load a kernel module from any path (see image above). File is not required, so we can load a kernel module on the fly, for example from memory or even from the network. We can download a chunk of data from the network, and it could be kernel module and we don’t have to write file – we can load this as a kernel module. This tool can load a kernel module without verification – no warning message and you don’t have to sign the kernel module. And if you do it our way, there is no need to patch kext.
The reason is this API (see image above), kext_request(). We use this API to load kernel module, so this API can help us load kernel module directly without any checking. As you can see, if you specify your own kernel module you have to follow the format and then you can use this API to load your kernel module. Of course you have to have the permission, the host privilege.
On this slide, you can see the source code (see image above). The code actually checks the host privilege, not your ID. With this host privilege you can start to load kernel module. One other important thing is you have to make your own mkext – it is the kernel module object. Here is the structure of the object and the sample of the plist (see image below).
You have to follow the format and you have to specify the offset size. So follow the specs and you can load your own kernel module with no warnings popping up.
Okay, let’s see our demo (watch video above). In this demo, first, we will show how to load kernel module using host privilege; and then, after loading kernel module, we will show you how to bypass the kernel module warning. So, we install the kernel module. This patch modifies the kernel data and so we grant host privilege to all users. Now even a normal user can load kernel module. Okay, now we will load kernel module the standard way, not our way. You can see the warning message because we are using the standard way to load kernel module. As you can see, it’s a normal user, not root and not a privileged user, but our kernel patch grants permissions to this user, to all users actually. This is the kernel module we’ve just loaded. As you see, we used mykextload to load kernel module. And this time, there is no warning message and the kernel module is loaded.