diff options
author | Luca Deri <deri@ntop.org> | 2021-04-26 10:17:29 +0200 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2021-04-26 10:17:29 +0200 |
commit | 4a09707e4868cecb62cd8b115ea5eaf1cfa4f835 (patch) | |
tree | d7f2242326c2cb678284428f19e9e79a6557ad79 | |
parent | a04efb7ce76b796ec73decc1ec18827b51b0cb32 (diff) |
Added flow risk to wireshark dissection
-rw-r--r-- | example/ndpiReader.c | 10 | ||||
-rw-r--r-- | example/reader_util.c | 24 | ||||
-rw-r--r-- | example/reader_util.h | 53 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | wireshark/ndpi.lua | 69 |
5 files changed, 122 insertions, 37 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 00d62ffef..3a88c0aab 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -172,10 +172,12 @@ struct receiver { struct receiver *receivers = NULL, *topReceivers = NULL; +#define WIRESHARK_NTOP_MAGIC 0x19680924 struct ndpi_packet_trailer { - u_int32_t magic; /* 0x19682017 */ + u_int32_t magic; /* WIRESHARK_NTOP_MAGIC */ u_int16_t master_protocol /* e.g. HTTP */, app_protocol /* e.g. FaceBook */; + ndpi_risk flow_risk; char name[16]; }; @@ -3217,6 +3219,7 @@ static void ndpi_process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { struct ndpi_proto p; + ndpi_risk flow_risk; u_int16_t thread_id = *((u_int16_t*)args); /* allocate an exact size buffer to check overflows */ @@ -3226,7 +3229,7 @@ static void ndpi_process_packet(u_char *args, return ; } memcpy(packet_checked, packet, header->caplen); - p = ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked, csv_fp); + p = ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked, &flow_risk, csv_fp); if(!pcap_start.tv_sec) pcap_start.tv_sec = header->ts.tv_sec, pcap_start.tv_usec = header->ts.tv_usec; pcap_end.tv_sec = header->ts.tv_sec, pcap_end.tv_usec = header->ts.tv_usec; @@ -3281,7 +3284,8 @@ static void ndpi_process_packet(u_char *args, trailer = (struct ndpi_packet_trailer*)&extcap_buf[h.caplen]; memcpy(extcap_buf, packet, h.caplen); memset(trailer, 0, sizeof(struct ndpi_packet_trailer)); - trailer->magic = htonl(0x19680924); + trailer->magic = htonl(WIRESHARK_NTOP_MAGIC); + trailer->flow_risk = htonl(flow_risk); trailer->master_protocol = htons(p.master_protocol), trailer->app_protocol = htons(p.app_protocol); ndpi_protocol2name(ndpi_thread_info[thread_id].workflow->ndpi_struct, p, trailer->name, sizeof(trailer->name)); crc = (uint32_t*)&extcap_buf[h.caplen+sizeof(struct ndpi_packet_trailer)]; diff --git a/example/reader_util.c b/example/reader_util.c index 0e6cd8e97..b95168e8d 100644 --- a/example/reader_util.c +++ b/example/reader_util.c @@ -1306,8 +1306,9 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, u_int16_t ipsize, u_int16_t rawsize, const struct pcap_pkthdr *header, const u_char *packet, - pkt_timeval when, - FILE * csv_fp) { + pkt_timeval when, + ndpi_risk *flow_risk, + FILE * csv_fp) { struct ndpi_id_struct *src, *dst; struct ndpi_flow_info *flow = NULL; struct ndpi_flow_struct *ndpi_flow = NULL; @@ -1539,6 +1540,18 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, } } +#if 0 + if(flow->risk != 0) { + FILE *r = fopen("/tmp/e", "a"); + + if(r) { + fprintf(r, "->>> %u [%08X]\n", flow->risk, flow->risk); + fclose(r); + } + } +#endif + + *flow_risk = flow->risk; return(flow->detected_protocol); } @@ -1567,6 +1580,7 @@ int ndpi_is_datalink_supported(int datalink_type) struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, const struct pcap_pkthdr *header, const u_char *packet, + ndpi_risk *flow_risk, FILE * csv_fp) { /* * Declare pointers to packet headers @@ -1615,6 +1629,8 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, /* counters */ u_int8_t vlan_packet = 0; + *flow_risk = 0 /* NDPI_NO_RISK */; + /* Increment raw packet counter */ workflow->stats.raw_packet_count++; @@ -1638,7 +1654,6 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, datalink_type = (int)pcap_datalink(workflow->pcap_handle); #endif - datalink_check: // 20 for min iph and 8 for min UDP if(header->caplen < eth_offset + 28) @@ -1730,7 +1745,6 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, if(header->caplen < (eth_offset + radio_len + sizeof(struct ndpi_wifi_header))) return(nproto); - /* Calculate 802.11 header length (variable) */ wifi = (struct ndpi_wifi_header*)( packet + eth_offset + radio_len); fc = wifi->fc; @@ -2030,7 +2044,7 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, return(packet_processing(workflow, time_ms, vlan_id, tunnel_type, iph, iph6, ip_offset, header->caplen - ip_offset, header->caplen, header, packet, header->ts, - csv_fp)); + flow_risk, csv_fp)); } /* ********************************************************** */ diff --git a/example/reader_util.h b/example/reader_util.h index 5ec8b558c..c54d68aa4 100644 --- a/example/reader_util.h +++ b/example/reader_util.h @@ -94,38 +94,38 @@ extern int dpdk_port_deinit(int port); // inner hash table (ja3 -> security state) typedef struct ndpi_ja3_info { - char * ja3; - ndpi_cipher_weakness unsafe_cipher; - UT_hash_handle hh; + char * ja3; + ndpi_cipher_weakness unsafe_cipher; + UT_hash_handle hh; } ndpi_ja3_info; // external hash table (host ip -> <ip string, hash table ja3c, hash table ja3s>) // used to aggregate ja3 fingerprints by hosts typedef struct ndpi_host_ja3_fingerprints { - u_int32_t ip; - char *ip_string; - char *dns_name; - ndpi_ja3_info *host_client_info_hasht; - ndpi_ja3_info *host_server_info_hasht; + u_int32_t ip; + char *ip_string; + char *dns_name; + ndpi_ja3_info *host_client_info_hasht; + ndpi_ja3_info *host_server_info_hasht; - UT_hash_handle hh; + UT_hash_handle hh; } ndpi_host_ja3_fingerprints; //inner hash table typedef struct ndpi_ip_dns{ - u_int32_t ip; - char *ip_string; - char *dns_name; //server name if any; - UT_hash_handle hh; + u_int32_t ip; + char *ip_string; + char *dns_name; //server name if any; + UT_hash_handle hh; } ndpi_ip_dns; //hash table ja3 -> <host, ip, security>, used to aggregate host by ja3 fingerprints typedef struct ndpi_ja3_fingerprints_host{ - char *ja3; //key - ndpi_cipher_weakness unsafe_cipher; - ndpi_ip_dns *ipToDNS_ht; - UT_hash_handle hh; + char *ja3; //key + ndpi_cipher_weakness unsafe_cipher; + ndpi_ip_dns *ipToDNS_ht; + UT_hash_handle hh; } ndpi_ja3_fingerprints_host; struct flow_metrics { @@ -294,14 +294,14 @@ typedef struct ndpi_workflow { void **ndpi_flows_root; struct ndpi_detection_module_struct *ndpi_struct; u_int32_t num_allocated_flows; - } ndpi_workflow_t; +} ndpi_workflow_t; /* TODO: remove wrappers parameters and use ndpi global, when their initialization will be fixed... */ struct ndpi_workflow * ndpi_workflow_init(const struct ndpi_workflow_prefs * prefs, pcap_t * pcap_handle); - /* workflow main free function */ +/* workflow main free function */ void ndpi_workflow_free(struct ndpi_workflow * workflow); @@ -316,7 +316,8 @@ void ndpi_free_flow_info_half(struct ndpi_flow_info *flow); struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, const struct pcap_pkthdr *header, const u_char *packet, - FILE * csv_fp); + ndpi_risk *flow_risk, + FILE * csv_fp); int ndpi_is_datalink_supported(int datalink_type); @@ -334,7 +335,7 @@ static inline void ndpi_workflow_set_flow_giveup_callback(struct ndpi_workflow * workflow->__flow_giveup_udata = udata; } - /* compare two nodes in workflow */ +/* compare two nodes in workflow */ int ndpi_workflow_node_cmp(const void *a, const void *b); void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_flow_info *flow, FILE * csv_fp); u_int32_t ethernet_crc32(const void* data, size_t n_bytes); @@ -346,13 +347,13 @@ float ndpi_flow_get_byte_count_entropy(const uint32_t byte_count[256], unsigned extern int nDPI_LogLevel; #ifdef NDPI_ENABLE_DEBUG_MESSAGES - #define LOG(log_level, args...) \ - { \ - if(log_level <= nDPI_LogLevel) \ - printf(args); \ +#define LOG(log_level, args...) \ + { \ + if(log_level <= nDPI_LogLevel) \ + printf(args); \ } #else - #define LOG(...) {} +#define LOG(...) {} #endif #endif diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 5fc4ca06e..54a5caaf6 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -62,9 +62,10 @@ typedef enum { /* NOTE When the typedef below is modified don't forget to update + - nDPI/wireshark/ndpi.lua - ndpi_risk2str (in ndpi_utils.c) - https://github.com/ntop/ntopng/blob/dev/scripts/lua/modules/flow_risk_utils.lua - - ndpi_risk_enum (in python/ndpi.py) + - ndpi_risk_enum (in python/ndpi.py) */ typedef enum { NDPI_NO_RISK = 0, diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua index 51e0cb388..b594c5697 100644 --- a/wireshark/ndpi.lua +++ b/wireshark/ndpi.lua @@ -26,6 +26,8 @@ local ndpi_fds = ndpi_proto.fields ndpi_fds.network_protocol = ProtoField.new("nDPI Network Protocol", "ndpi.protocol.network", ftypes.UINT8, nil, base.DEC) ndpi_fds.application_protocol = ProtoField.new("nDPI Application Protocol", "ndpi.protocol.application", ftypes.UINT8, nil, base.DEC) ndpi_fds.name = ProtoField.new("nDPI Protocol Name", "ndpi.protocol.name", ftypes.STRING) +ndpi_fds.flow_risk = ProtoField.new("nDPI Flow Risk", "ndpi.flow_risk", ftypes.UINT32, nil, base.DEC) +ndpi_fds.flow_risk_str = ProtoField.new("nDPI Flow Risk String", "ndpi.flow_risk_str", ftypes.STRING) local ntop_proto = Proto("ntop", "ntop Extensions") ntop_proto.fields = {} @@ -886,6 +888,65 @@ function latency_dissector(tvb, pinfo, tree) end end + +function bit(p) + return 2 ^ (p - 1) -- 1-based indexing +end + +function hasbit(x, p) + return x % (p + p) >= p +end + +local ndpi_risks = { + ['0'] = "No Risk", + ['1'] = "XSS attack", + ['2'] = "SQL injection", + ['3'] = "RCE injection", + ['4'] = "Binary application transfer", + ['5'] = "Known protocol on non standard port", + ['6'] = "Self-signed Certificate", + ['7'] = "Obsolete TLS version (< 1.1)", + ['8'] = "Weak TLS cipher", + ['9'] = "TLS Expired Certificate", + ['10'] = "TLS Certificate Mismatch", + ['11'] = "HTTP Suspicious User-Agent", + ['12'] = "HTTP Numeric IP Address", + ['13'] = "HTTP Suspicious URL", + ['14'] = "HTTP Suspicious Header", + ['15'] = "TLS (probably) not carrying HTTPS", + ['16'] = "Suspicious DGA domain name", + ['17'] = "Malformed packet", + ['18'] = "SSH Obsolete Client Version/Cipher", + ['19'] = "SSH Obsolete Server Version/Cipher", + ['20'] = "SMB Insecure Version", + ['21'] = "TLS Suspicious ESNI Usage", + ['22'] = "Unsafe Protocol", + ['23'] = "Suspicious DNS traffic", + ['24'] = "SNI TLS extension was missing", + ['25'] = "HTTP suspicious content", + ['26'] = "Risky ASN", + ['27'] = "Risky domain name", + ['28'] = "Possibly Malicious JA3 Fingerprint", + ['29'] = "Possibly Malicious SSL Certificate SHA1 Fingerprint", + ['30'] = "Desktop/File Sharing Session", + ['31'] = "" +} + +function map_ndpi_risk(r) + local ret = "" + + if(r ~= 0) then + for i=0,31 do + if(hasbit(r, bit(i))) then + ret = ret.."["..ndpi_risks[(i-1)..""].."]" + end + end + end + + return(ret) +end + + -- the dissector function callback function ndpi_proto.dissector(tvb, pinfo, tree) -- Wireshark dissects the packet twice. We ignore the first @@ -918,14 +979,18 @@ function ndpi_proto.dissector(tvb, pinfo, tree) local ndpi_subtree = tree:add(ndpi_proto, tvb(), "nDPI Protocol") local network_protocol = tonumber(elems[2]..elems[3], 16) -- 16 = HEX local application_protocol = tonumber(elems[4]..elems[5], 16) -- 16 = HEX + local str_risk = elems[6]..elems[7]..elems[8]..elems[9] + local flow_risk = tonumber(str_risk, 16) -- 16 = HEX local name = "" - for i=6,21 do + for i=10,25 do name = name .. string.char(tonumber(elems[i], 16)) end ndpi_subtree:add(ndpi_fds.network_protocol, network_protocol) ndpi_subtree:add(ndpi_fds.application_protocol, application_protocol) + ndpi_subtree:add(ndpi_fds.flow_risk, flow_risk) + ndpi_subtree:add(ndpi_fds.flow_risk_str, map_ndpi_risk(flow_risk)) ndpi_subtree:add(ndpi_fds.name, name) if(application_protocol ~= 0) then @@ -954,7 +1019,7 @@ function ndpi_proto.dissector(tvb, pinfo, tree) for k,v in pairsByValues(ndpi_flows, asc) do if(k ~= flowkey) then - table.remove(ndpi_flows, k) + ndpi_flows[k] = nil -- Remove entry num_ndpi_flows = num_ndpi_flows + 1 if(num_ndpi_flows == (2*max_num_entries)) then break |