diff options
-rw-r--r-- | python/ndpi.py | 2 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 9 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 10 | ||||
-rw-r--r-- | src/lib/protocols/dns.c | 30 | ||||
-rw-r--r-- | tests/result/malformed_dns.pcap.out | 2 | ||||
-rw-r--r-- | wireshark/ndpi.lua | 4 |
7 files changed, 52 insertions, 8 deletions
diff --git a/python/ndpi.py b/python/ndpi.py index 7a57e1a39..db87633ac 100644 --- a/python/ndpi.py +++ b/python/ndpi.py @@ -328,6 +328,8 @@ typedef enum { NDPI_TLS_FATAL_ALERT, NDPI_SUSPICIOUS_ENTROPY, NDPI_CLEAR_TEXT_CREDENTIALS, + NDPI_DNS_LARGE_PACKET, + NDPI_DNS_FRAGMENTED, /* Leave this as last member */ NDPI_MAX_RISK diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 9f58075d8..9a9edfc3e 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -115,6 +115,8 @@ typedef enum { NDPI_TLS_FATAL_ALERT, NDPI_SUSPICIOUS_ENTROPY, NDPI_CLEAR_TEXT_CREDENTIALS, + NDPI_DNS_LARGE_PACKET, + NDPI_DNS_FRAGMENTED, /* Leave this as last member */ NDPI_MAX_RISK /* must be <= 63 due to (**) */ @@ -150,7 +152,6 @@ typedef struct { risk_percentage default_client_risk_pctg; /* 0-100 */ } ndpi_risk_info; - /* NDPI_VISIT */ typedef enum { ndpi_preorder, diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 4f96120e0..854c5375a 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -104,6 +104,8 @@ static ndpi_risk_info ndpi_known_risks[] = { { NDPI_TLS_FATAL_ALERT, NDPI_RISK_LOW, CLIENT_FAIR_RISK_PERCENTAGE }, { NDPI_SUSPICIOUS_ENTROPY, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE }, { NDPI_CLEAR_TEXT_CREDENTIALS, NDPI_RISK_HIGH, CLIENT_HIGH_RISK_PERCENTAGE }, + { NDPI_DNS_LARGE_PACKET, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE }, + { NDPI_DNS_FRAGMENTED, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE }, /* Leave this as last member */ { NDPI_MAX_RISK, NDPI_RISK_LOW, CLIENT_FAIR_RISK_PERCENTAGE } @@ -7495,8 +7497,9 @@ int ndpi_check_dga_name(struct ndpi_detection_module_struct *ndpi_str, int rc = ndpi_dga_function(name, is_hostname); if(rc) { - if(flow) + if(flow) { ndpi_set_risk(ndpi_str, flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + } } return(rc); @@ -7632,7 +7635,9 @@ int ndpi_check_dga_name(struct ndpi_detection_module_struct *ndpi_str, */ || ((max_domain_element_len >= 19 /* word too long. Example bbcbedxhgjmdobdprmen.com */) && ((num_char_repetitions > 1) || (num_digits > 1))) ) { - if(flow) ndpi_set_risk(ndpi_str, flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + if(flow) { + ndpi_set_risk(ndpi_str, flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + } if(ndpi_verbose_dga_detection) printf("[DGA] Found!"); diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index ed5ffd228..9c77e6d92 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -1782,10 +1782,16 @@ const char* ndpi_risk2str(ndpi_risk_enum risk) { case NDPI_SUSPICIOUS_ENTROPY: return("Suspicious entropy"); - + case NDPI_CLEAR_TEXT_CREDENTIALS: return("Clear-text credentials"); - + + case NDPI_DNS_LARGE_PACKET: + return("DNS packet larger than 512 bytes"); + + case NDPI_DNS_FRAGMENTED: + return("Fragmented DNS message"); + default: snprintf(buf, sizeof(buf), "%d", (int)risk); return(buf); diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index 5e1f100cc..0d3ac276d 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -35,6 +35,8 @@ #define LLMNR_PORT 5355 #define MDNS_PORT 5353 +#define PKT_LEN_ALERT 512 + static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); @@ -333,6 +335,8 @@ static int search_dns_again(struct ndpi_detection_module_struct *ndpi_struct, st /* *********************************************** */ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + + int payload_offset; u_int8_t is_query; u_int16_t s_port = 0, d_port = 0; @@ -513,8 +517,31 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st if(flow->packet_counter > 3) NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + + if((flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_DNS) + || (flow->packet.detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) { + + if(flow->packet.udp != NULL && flow->packet.payload_packet_len > PKT_LEN_ALERT) + ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET); + + const struct ndpi_iphdr *iph = flow->packet.iph; + const u_int8_t *l3 = (const u_int8_t *) flow->packet.iph; + const struct ndpi_ipv6hdr *iph_v6 = NULL; + const u_int16_t ipsize = flow->packet.l3_packet_len; + + // TODO: add support to RFC6891 to avoid some false positive + if(iph != NULL && iph->version == 6 && ipsize >= sizeof(struct ndpi_ipv6hdr)) { + iph_v6 = (const struct ndpi_ipv6hdr *) l3; + iph = NULL; + } + + if((iph != NULL && (ipsize < iph->ihl * 4 || ipsize < ntohs(iph->tot_len) || ntohs(iph->tot_len) < iph->ihl * 4 + || ((iph->frag_off & htons(0x1FFF)) != 0) || ((iph->frag_off & htons(0x3FFF)) != 0))) + || (iph_v6 != NULL && iph_v6->ip6_hdr.ip6_un1_nxt == 44)) + ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED); + + } } - void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { ndpi_set_bitmask_protocol_detection("DNS", ndpi_struct, detection_bitmask, *id, @@ -525,4 +552,5 @@ void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, ADD_TO_DETECTION_BITMASK); *id += 1; + } diff --git a/tests/result/malformed_dns.pcap.out b/tests/result/malformed_dns.pcap.out index 6ea94ac26..18e85b64d 100644 --- a/tests/result/malformed_dns.pcap.out +++ b/tests/result/malformed_dns.pcap.out @@ -4,4 +4,4 @@ DPI Packets (UDP): 2 (2.00 pkts/flow) DNS 6 5860 1 - 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][ClearText][cat: Network/14][2 pkts/140 bytes <-> 4 pkts/5720 bytes][Goodput ratio: 40/97][5.03 sec][Host: www.xt.com][0.0.0.0][bytes ratio: -0.952 (Download)][IAT c2s/s2c min/avg/max/stddev: 4999/13 4999/1670 4999/4983 0/2343][Pkt Len c2s/s2c min/avg/max/stddev: 70/1430 70/1430 70/1430 0/0][Risk: ** Malformed packet **][Risk Score: 10][PLAIN TEXT (AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)][Plen Bins: 33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,0,0,0,0] + 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][ClearText][cat: Network/14][2 pkts/140 bytes <-> 4 pkts/5720 bytes][Goodput ratio: 40/97][5.03 sec][Host: www.xt.com][0.0.0.0][bytes ratio: -0.952 (Download)][IAT c2s/s2c min/avg/max/stddev: 4999/13 4999/1670 4999/4983 0/2343][Pkt Len c2s/s2c min/avg/max/stddev: 70/1430 70/1430 70/1430 0/0][Risk: ** Malformed packet **** DNS packet is larger than 512 bytes **][Risk Score: 60][PLAIN TEXT (AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)][Plen Bins: 33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,0,0,0,0] diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua index d2737ac71..643dc3235 100644 --- a/wireshark/ndpi.lua +++ b/wireshark/ndpi.lua @@ -75,9 +75,11 @@ flow_risks[33] = ProtoField.bool("ndpi.flow_risk.suspicious_extension", "TLS sus flow_risks[34] = ProtoField.bool("ndpi.flow_risk.fatal_alert", "TLS fatal alert detected", num_bits_flow_risks, nil, bit(2), "nDPI Flow Risk: TLS fatal alert") flow_risks[35] = ProtoField.bool("ndpi.flow_risk.suspicious_entropy", "Suspicious entropy", num_bits_flow_risks, nil, bit(3), "nDPI Flow Risk: suspicious entropy") flow_risks[36] = ProtoField.bool("ndpi.flow_risk.clear_text_credentials", "Cleat-Text credentials", num_bits_flow_risks, nil, bit(3), "nDPI Flow Risk: cleat-text credentials") +flow_risks[37] = ProtoField.bool("ndpi.flow_risk.dns_large_packet", "DNS large packet", num_bits_flow_risks, nil, bit(4), "nDPI Flow Risk: DNS packet is larger than 512 bytes") +flow_risks[38] = ProtoField.bool("ndpi.flow_risk.dns_fragmented", "DNS fragmented", num_bits_flow_risks, nil, bit(5), "nDPI Flow Risk: DNS message is fragmented") -- Last one: keep in sync the bitmask when adding new risks!! -flow_risks[64] = ProtoField.new("Unused", "ndpi.flow_risk.unused", ftypes.UINT32, nil, base.HEX, bit(32) - bit(4)) +flow_risks[64] = ProtoField.new("Unused", "ndpi.flow_risk.unused", ftypes.UINT32, nil, base.HEX, bit(32) - bit(7)) for _,v in pairs(flow_risks) do ndpi_fds[#ndpi_fds + 1] = v |