diff options
author | Luca Deri <deri@ntop.org> | 2021-12-23 21:30:16 +0100 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2021-12-23 21:30:16 +0100 |
commit | c4ac53a03fa1fbfd5a5d7fea507cfcbe5b307914 (patch) | |
tree | dcf5ab420ea7c835b1eb5eaf4be718d2f257a81b /src/lib/protocols | |
parent | fdb6481cd6d019651faea6cdd962db099cbf20a3 (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.c | 100 |
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; } |