Goofkit is an inline function hooking and trampolining rootkit. Goofkit uses inline hooking and trampolining to create a more robust and better hidden rootkit. Goofkit does not modify the system call table instead it inserts hooks into the system calls itself.
- Process hiding
- Hide processes from the /proc directory
- File hiding
- Hides files from the getdents call
- Hiding itself
- Unlinks itself from the kobject list and the init list
- File ACLs (broken?)
- Returns error when specifi files attempt to open
- Netfilter hook - WIP
- Privelege escalation - WIP
| Debian 8 Jessie | Debian 9 Stretch | | Kernel: 3.16.0-4-amd64 | Kernel: 4.9.0-7-amd64 | | * uname ✅ | * uname ✅ | | * getdents ✅ | * getdents ✅ | | * kill ✅ | * kill ✅ | -------------------------------------------------------- | Centos 7 | | | Kernel: 3.10.0-957 | | | * uname 🚫 | | | * getdents ✅ | | | * kill 🚫 | |
- Centos 7 kill error * Seems to make it through syscall kernel crashes after goofy_kill returns.
Instead of using the standard method of system call hooking (overwriting the system call table) Goofkit inserts a jump instruction to change the code flow.
\x48\xb8\x88\x77\x66\x55\x44\x33\x22\x11\x48\x89\xc0\xff\xe0 0: 48 b8 88 77 66 55 44 movabs rax,0x1122334455667788 ; load address into RAX 7: 33 22 11 a: 48 89 c0 mov rax,rax ; required but not sure why d: ff e0 jmp rax ; jump to address
When copying these instructions into the systemcall its important to not cut instructions in half. If the instruction is cut in half it will result in garbage bytes in the instructions which will casaue the kernel to crash.
To avoid cutting instructions in half Goofkit uses an LDE (currently BeaEngine) to measure the length of each instruction. Goofkit will calculate the number of 1 byte nop instructions it needs to append to the hook so that insturctions are not cut.
A simplified version of how the LDE is used is shown here:
while len < hook_len: len += len(*eip) eip += len
Trampolining is the reason Goofkit is able to do inline function hooking without multiple writes to the system calls. When a rookit uses inline hooking and wants to pause a specific hook or all malicious behavior it needs to rewrite the systemcall each time. Trampolining allows Goofkit to seemlessly resume normal execution. Instead of rewriting the system call execution can be passed along through the malicious hook to the trampoline and subsequently the original function.
syscall_open --> malicious_open --> open_trampoline --> syscall_open+offset_of_hook
To create a new hook you will need to do the following:
- Increment the
HOOKS_COUNT
macro - Define a "goofy" function
goofy_open()
in goof.h - Write your function in goof.c
- Add a hook:
a. Ingoof_init
add acreate_tramp
call. Specify the source (eg.sys_close
). Specify the goof function. Provide an ID number < HOOKS_COUNT. Specify the byte count provided by thenumber_of_bytes_to_pad_jump
function.
b. Ingoof_exit
add a remove function passing the ID number of the hook from the previous step.