Introduction
We recently released a new userland rootkit on BHL named Azazel. It's similar to previous versions of Jynx/Jynx2, but is more advanced and focused on anti-debugging and anti-detection methods. This leads us into a current major problem with rootkit detection mechanisms such as rkhunter. Put simply, if you run these tools in a potentially compromised environment, you cannot trust their output. Rkhunter relies primarily on signature detection which is fine for known threats that use default values and file names, but here's a simple detection method that compares the address of syscalls loaded directly from libc, and the "next" address to that system call. By comparing the two values, you can more accurately detect preload based userland rootkits.
#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> #define LIBC "/lib/x86_64-linux-gnu/libc.so.6" int main(int argc, char *argv[]) { void *libc = dlopen(LIBC, RTLD_LAZY); // Open up libc directly char *syscalls[] = {"open", "readdir", "fopen", "accept", "access", "unlink"}; int i; void *(*libc_func)(); void *(*next_func)(); for (i = 0; i < 6; ++i) { printf("[+] Checking %s syscall.\n", syscalls[i]); libc_func = dlsym(libc, syscalls[i]); next_func = dlsym(RTLD_NEXT, syscalls[i]); if (libc_func != next_func) { printf("[!] Preload hooks dectected!\n"); printf("Libc address: %p\n", libc_func); printf("Next address: %p\n", next_func); } } return 0; }
$ gcc preloadcheck.c -o preloadcheck -ldl $ ./preloadcheck [+] Checking open syscall. [+] Checking readdir syscall. [+] Checking fopen syscall. [+] Checking accept syscall. [+] Checking access syscall. [+] Checking unlink syscall.Now here's an example run against Azazel.
$ LD_PRELOAD=/lib/libselinux.so ./preloadcheck [+] Checking open syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf65a890 Next address: 0x7fe1bfb1d932 [+] Checking readdir syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf633c50 Next address: 0x7fe1bfb1dc56 [+] Checking fopen syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf5f46c0 Next address: 0x7fe1bfb1d6c6 [+] Checking accept syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf6676a0 Next address: 0x7fe1bfb1eb4a [+] Checking access syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf65ab40 Next address: 0x7fe1bfb1d670 [+] Checking unlink syscall. [!] Preload hooks dectected! Libc address: 0x7fe1bf65bd50 Next address: 0x7fe1bfb1db58
Note: This is not an end all to preload kits. As we have seen with Azazel, kits are still able to selectively filter results or unhook specific programs to avoid detection. It is also important to note that by hooking libdl.so's functions themselves, one could even evade this detection mechanism.