aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
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 /src/lib/protocols
parentfdb6481cd6d019651faea6cdd962db099cbf20a3 (diff)
Added support for Log4J/Log4Shell detection in nDPI via a new flow risk named NDPI_POSSIBLE_EXPLOIT
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/http.c100
1 files changed, 62 insertions, 38 deletions
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;
}