diff options
author | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2024-10-28 23:36:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-28 23:36:51 +0100 |
commit | 9da99075aa174a7ecfc00fb9a18d32d3056d8db3 (patch) | |
tree | e3ad461c6c651cc5b179f1c8dc7180523c1add69 | |
parent | dc125dc2a8a3aebd9accfd2deaae7dbecb5aae5a (diff) |
TLS: export heuristic fingerprint as metadata (#2609)
-rw-r--r-- | example/ndpiReader.c | 17 | ||||
-rw-r--r-- | example/reader_util.c | 4 | ||||
-rw-r--r-- | example/reader_util.h | 2 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 10 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 14 | ||||
-rw-r--r-- | wireshark/ndpi.lua | 26 |
7 files changed, 71 insertions, 4 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 0de290724..65ddb4ca3 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -228,6 +228,7 @@ struct receiver *receivers = NULL, *topReceivers = NULL; #define WIRESHARK_METADATA_SERVERNAME 0x01 #define WIRESHARK_METADATA_JA4C 0x02 +#define WIRESHARK_METADATA_TLS_HEURISTICS_MATCHING_FINGERPRINT 0x03 struct ndpi_packet_tlv { u_int16_t type; @@ -4674,6 +4675,22 @@ static void ndpi_process_packet(u_char *args, tot_len += 4 + htons(tlv->length); tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; } + if(flow->ssh_tls.obfuscated_heur_matching_set.pkts[0] != 0) { + tlv->type = ntohs(WIRESHARK_METADATA_TLS_HEURISTICS_MATCHING_FINGERPRINT); + tlv->length = ntohs(sizeof(struct ndpi_tls_obfuscated_heuristic_matching_set)); + struct ndpi_tls_obfuscated_heuristic_matching_set *s = (struct ndpi_tls_obfuscated_heuristic_matching_set *)tlv->data; + s->bytes[0] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.bytes[0]); + s->bytes[1] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.bytes[1]); + s->bytes[2] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.bytes[2]); + s->bytes[3] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.bytes[3]); + s->pkts[0] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.pkts[0]); + s->pkts[1] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.pkts[1]); + s->pkts[2] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.pkts[2]); + s->pkts[3] = ntohl(flow->ssh_tls.obfuscated_heur_matching_set.pkts[3]); + /* TODO: boundary check */ + tot_len += 4 + htons(tlv->length); + tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; + } flow->detection_completed = 2; /* Avoid exporting metadata again. If we really want to have the metadata on Wireshark for *all* diff --git a/example/reader_util.c b/example/reader_util.c index efa42da22..6c463fdbb 100644 --- a/example/reader_util.c +++ b/example/reader_util.c @@ -1583,6 +1583,10 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl } } + if(flow->ndpi_flow->tls_quic.obfuscated_heur_state && flow->ndpi_flow->tls_quic.obfuscated_heur_matching_set) + memcpy(&flow->ssh_tls.obfuscated_heur_matching_set, flow->ndpi_flow->tls_quic.obfuscated_heur_matching_set, + sizeof(struct ndpi_tls_obfuscated_heuristic_matching_set)); + if(!monitoring_enabled) { add_to_address_port_list(&flow->stun.mapped_address, &flow->ndpi_flow->stun.mapped_address); add_to_address_port_list(&flow->stun.peer_address, &flow->ndpi_flow->stun.peer_address); diff --git a/example/reader_util.h b/example/reader_util.h index 5c4acbb90..eea3ce454 100644 --- a/example/reader_util.h +++ b/example/reader_util.h @@ -302,6 +302,8 @@ typedef struct ndpi_flow_info { ndpi_cipher_weakness client_unsafe_cipher, server_unsafe_cipher; u_int32_t quic_version; + + struct ndpi_tls_obfuscated_heuristic_matching_set obfuscated_heur_matching_set; } ssh_tls; struct { diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index fc6a6c837..d2931ece5 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1260,6 +1260,11 @@ struct os_fingerprint { enum operating_system_hint os; }; +struct ndpi_tls_obfuscated_heuristic_matching_set { + u_int32_t bytes[4]; + u_int32_t pkts[4]; +}; + struct ndpi_flow_struct { u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE]; @@ -1373,6 +1378,7 @@ struct ndpi_flow_struct { message_t message[2]; /* Directions */ u_int8_t certificate_processed:1, change_cipher_from_client:1, change_cipher_from_server:1, from_opportunistic_tls:1, pad:4; struct tls_obfuscated_heuristic_state *obfuscated_heur_state; + struct ndpi_tls_obfuscated_heuristic_matching_set *obfuscated_heur_matching_set; } tls_quic; /* Used also by DTLS and POPS/IMAPS/SMTPS/FTPS */ union { @@ -1608,8 +1614,8 @@ struct ndpi_flow_struct { _Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 264, "Size of the struct member protocols increased to more than 264 bytes, " "please check if this change is necessary."); -_Static_assert(sizeof(struct ndpi_flow_struct) <= 1192, - "Size of the flow struct increased to more than 1192 bytes, " +_Static_assert(sizeof(struct ndpi_flow_struct) <= 1200, + "Size of the flow struct increased to more than 1200 bytes, " "please check if this change is necessary."); #endif #endif diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 5298f8291..98873e959 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -6817,6 +6817,8 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { if(flow->tls_quic.obfuscated_heur_state) ndpi_free(flow->tls_quic.obfuscated_heur_state); + if(flow->tls_quic.obfuscated_heur_matching_set) + ndpi_free(flow->tls_quic.obfuscated_heur_matching_set); } } diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 048060188..498147181 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -380,6 +380,20 @@ static int tls_obfuscated_heur_search(struct ndpi_detection_module_struct* ndpi_ NDPI_LOG_DBG2(ndpi_struct, "TLS-Obf-Heur: set %d completed\n", i); if(check_set(ndpi_struct, set)) { /* Heuristic match */ + + /* Export the matching set as metadata */ + flow->tls_quic.obfuscated_heur_matching_set = ndpi_calloc(1, sizeof(struct ndpi_tls_obfuscated_heuristic_matching_set)); + if(flow->tls_quic.obfuscated_heur_matching_set) { + flow->tls_quic.obfuscated_heur_matching_set->bytes[0] = set->bytes[0]; + flow->tls_quic.obfuscated_heur_matching_set->bytes[1] = set->bytes[1]; + flow->tls_quic.obfuscated_heur_matching_set->bytes[2] = set->bytes[2]; + flow->tls_quic.obfuscated_heur_matching_set->bytes[3] = set->bytes[3]; + flow->tls_quic.obfuscated_heur_matching_set->pkts[0] = set->pkts[0]; + flow->tls_quic.obfuscated_heur_matching_set->pkts[1] = set->pkts[1]; + flow->tls_quic.obfuscated_heur_matching_set->pkts[2] = set->pkts[2]; + flow->tls_quic.obfuscated_heur_matching_set->pkts[3] = set->pkts[3]; + } + return 2; /* Found */ } else { /* Close this set and open a new one... */ diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua index 5f5531d08..ffbed1469 100644 --- a/wireshark/ndpi.lua +++ b/wireshark/ndpi.lua @@ -70,6 +70,7 @@ local mtd_types = { [0] = "Padding", [1] = "Server Name", [2] = "JA4C" + [3] = "TLS Heuristic Fingerprint", } ndpi_fds.metadata_type = ProtoField.new("nDPI Metadata Type", "ndpi.metadata.type", ftypes.UINT16, mtd_types) ndpi_fds.metadata_length = ProtoField.new("nDPI Metadata Length", "ndpi.metadata.length", ftypes.UINT16) @@ -78,6 +79,16 @@ ndpi_fds.metadata_value = ProtoField.new("nDPI Metadata Value", "ndpi.meta -- Specific fields ndpi_fds.metadata_server_name = ProtoField.new("nDPI Server Name", "ndpi.metadata.server_name", ftypes.STRING) ndpi_fds.metadata_ja4c = ProtoField.new("nDPI JA4C", "ndpi.metadata.ja4c", ftypes.STRING) +ndpi_fds.metadata = ProtoField.new("nDPI Metadata", "ndpi.metadata", ftypes.NONE) +ndpi_fds.metadata_tls_heuristic_fingerprint = ProtoField.new("nDPI TLS Heuristic Fingerprint", "ndpi.metadata.tls_heuristic_fingerprint", ftypes.NONE) +ndpi_fds.metadata_tls_heuristic_fingerprint_bytes0 = ProtoField.new("Bytes[0]", "ndpi.metadata.tls_heuristic_fingerprint.bytes0", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_bytes1 = ProtoField.new("Bytes[1]", "ndpi.metadata.tls_heuristic_fingerprint.bytes1", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_bytes2 = ProtoField.new("Bytes[2]", "ndpi.metadata.tls_heuristic_fingerprint.bytes2", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_bytes3 = ProtoField.new("Bytes[3]", "ndpi.metadata.tls_heuristic_fingerprint.bytes3", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_pkts0 = ProtoField.new("Pkts[0]", "ndpi.metadata.tls_heuristic_fingerprint.pkts0", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_pkts1 = ProtoField.new("Pkts[1]", "ndpi.metadata.tls_heuristic_fingerprint.pkts1", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_pkts2 = ProtoField.new("Pkts[2]", "ndpi.metadata.tls_heuristic_fingerprint.pkts2", ftypes.UINT32) +ndpi_fds.metadata_tls_heuristic_fingerprint_pkts3 = ProtoField.new("Pkts[3]", "ndpi.metadata.tls_heuristic_fingerprint.pkts3", ftypes.UINT32) local flow_risks = {} @@ -1965,8 +1976,19 @@ function ndpi_proto.dissector(tvb, pinfo, tree) metadata_tree:append_text(" ServerName: " .. trailer_tvb(offset + 4, mtd_length):string()) metadata_tree:add(ndpi_fds.metadata_server_name, trailer_tvb(offset + 4, mtd_length)) elseif mtd_type == 2 then - metadata_tree:append_text(" JA4C: " .. trailer_tvb(offset + 4, mtd_length):string()) - metadata_tree:add(ndpi_fds.metadata_ja4c, trailer_tvb(offset + 4, mtd_length)) + metadata_tree:append_text(" JA4C: " .. trailer_tvb(offset + 4, mtd_length):string()) + metadata_tree:add(ndpi_fds.metadata_ja4c, trailer_tvb(offset + 4, mtd_length)) + elseif mtd_type == 3 then + metadata_tree:append_text(" TLS Heuristic Fingerprint") + tls_tree = metadata_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint, trailer_tvb(offset + 4, mtd_length)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_bytes0, trailer_tvb(offset + 4, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_bytes1, trailer_tvb(offset + 8, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_bytes2, trailer_tvb(offset + 12, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_bytes3, trailer_tvb(offset + 16, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_pkts0, trailer_tvb(offset + 20, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_pkts1, trailer_tvb(offset + 24, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_pkts2, trailer_tvb(offset + 28, 4)) + tls_tree:add(ndpi_fds.metadata_tls_heuristic_fingerprint_pkts3, trailer_tvb(offset + 32, 4)) else -- Generic field metadata_tree:add(ndpi_fds.metadata_value, trailer_tvb(offset + 4, mtd_length)) |