diff options
author | Toni <matzeton@googlemail.com> | 2021-07-19 16:23:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-19 16:23:24 +0200 |
commit | 32275543c421eae55fd98a5a98e00059a0407953 (patch) | |
tree | 758cb9fdcb089880248cbb8e6f86f1482eb0099b /src/lib | |
parent | 57b8969a3d30cfdefe54fc46f4d5552d76bd1b82 (diff) |
Added risk: TLS_EXTENSION_SUSPICIOUS (#1252)
* validates client/server hello TLS extensions
* inspects content for some extensions
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/ndpi_main.c | 1 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 48 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 99 |
3 files changed, 130 insertions, 18 deletions
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index e1496b2d4..a9dc54aa1 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -103,6 +103,7 @@ static ndpi_risk_info ndpi_known_risks[] = { { NDPI_DESKTOP_OR_FILE_SHARING_SESSION, NDPI_RISK_LOW, CLIENT_FAIR_RISK_PERCENTAGE }, { NDPI_TLS_UNCOMMON_ALPN, NDPI_RISK_MEDIUM, CLIENT_HIGH_RISK_PERCENTAGE }, { NDPI_TLS_CERT_VALIDITY_TOO_LONG, NDPI_RISK_MEDIUM, CLIENT_FAIR_RISK_PERCENTAGE }, + { NDPI_TLS_EXTENSION_SUSPICIOUS, NDPI_RISK_HIGH, 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 64e60800f..87b2b3e8a 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <errno.h> +#include <math.h> #include <sys/types.h> @@ -1735,6 +1736,8 @@ const char* ndpi_risk2str(ndpi_risk_enum risk) { case NDPI_TLS_CERT_VALIDITY_TOO_LONG: return("TLS certificate validity longer than 13 months"); + case NDPI_TLS_EXTENSION_SUSPICIOUS: + return("TLS extension suspicious"); default: snprintf(buf, sizeof(buf), "%d", (int)risk); @@ -2001,4 +2004,49 @@ void ndpi_set_risk(struct ndpi_flow_struct *flow, ndpi_risk_enum r) { flow->risk |= v; } +/* ******************************************************************** */ + +int ndpi_is_printable_string(char const * const str, size_t len) +{ + for (size_t i = 0; i < len; ++i) + { + if (ndpi_isprint(str[i]) == 0) + { + return 0; + } + } + + return 1; +} + +/* ******************************************************************** */ + +float ndpi_calculate_entropy(u_int8_t const * const buf, size_t len) +{ + float entropy = 0.0f; + u_int32_t byte_counters[256]; + memset(byte_counters, 0, sizeof(byte_counters)); + + for (size_t i = 0; i < len; ++i) + { + if (buf[i] == i) + { + byte_counters[i]++; + } + } + + for (size_t i = 0; i < sizeof(byte_counters) / sizeof(byte_counters[0]); ++i) + { + if (byte_counters[i] == 0) + { + continue; + } + + float p = 1.0f * byte_counters[i] / len; + entropy -= p * log2f(p); + } + + entropy *= -1.0f; + return entropy; +} diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 73d76ecae..b0730a1c3 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -222,19 +222,6 @@ void ndpi_search_tls_tcp_memory(struct ndpi_detection_module_struct *ndpi_struct /* **************************************** */ -/* Can't call libc functions from kernel space, define some stub instead */ - -#define ndpi_isalpha(ch) (((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) -#define ndpi_isdigit(ch) ((ch) >= '0' && (ch) <= '9') -#define ndpi_isspace(ch) (((ch) >= '\t' && (ch) <= '\r') || ((ch) == ' ')) -#define ndpi_isprint(ch) ((ch) >= 0x20 && (ch) <= 0x7e) -#define ndpi_ispunct(ch) (((ch) >= '!' && (ch) <= '/') || \ - ((ch) >= ':' && (ch) <= '@') || \ - ((ch) >= '[' && (ch) <= '`') || \ - ((ch) >= '{' && (ch) <= '~')) - -/* **************************************** */ - static void cleanupServerName(char *buffer, int buffer_len) { u_int i; @@ -527,6 +514,11 @@ static void processCertificateElements(struct ndpi_detection_module_struct *ndpi flow->protos.tls_quic_stun.tls_quic.client_requested_server_name, len, packet->payload_packet_len-i-len); #endif + if (ndpi_is_printable_string(dNSName, len) == 0) + { + ndpi_set_risk(flow, NDPI_TLS_EXTENSION_SUSPICIOUS); + } + if(matched_name == 0) { if(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] == '\0') matched_name = 1; /* No SNI */ @@ -1095,11 +1087,6 @@ static void tlsCheckUncommonALPN(struct ndpi_flow_struct *flow) "doq-i00" }; - /* - * If the ALPN list increases in size, iterating over all items for every incoming ALPN may - * have a performance impact. A hash map could solve this issue. - */ - char * alpn_start = flow->protos.tls_quic_stun.tls_quic.alpn; char * comma_or_nul = alpn_start; do { @@ -1165,6 +1152,75 @@ static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndp /* **************************************** */ +static void checkExtensions(struct ndpi_flow_struct * const flow, int is_dtls, + u_int16_t extension_id, u_int16_t extension_len, u_int16_t extension_payload_offset) +{ + struct ndpi_packet_struct const * const packet = &flow->packet; + + if (extension_payload_offset + extension_len > packet->payload_packet_len) + { +#ifdef DEBUG_TLS + printf("[TLS] extension length exceeds remaining packet length: %u > %u.\n", + extension_len, packet->payload_packet_len - extension_payload_offset); +#endif + ndpi_set_risk(flow, NDPI_TLS_EXTENSION_SUSPICIOUS); + return; + } + + /* see: https://www.wireshark.org/docs/wsar_html/packet-tls-utils_8h_source.html */ + static u_int16_t const allowed_non_iana_extensions[] = { + 65486 /* ESNI */, 13172 /* NPN - Next Proto Neg */, 17513 /* ALPS */, + 30032 /* Channel ID */, 65445 /* QUIC transport params */, + /* GREASE extensions */ + 2570, 6682, 10794, 14906, 19018, 23130, 27242, + 31354, 35466, 39578, 43690, 47802, 51914, 56026, + 60138, 64250, + /* Groups */ + 1035, 10794, 16696, 23130, 31354, 35466, 51914, + /* Ciphers */ + 102, 129, 52243, 52244, 57363, 65279, 65413 + }; + size_t const allowed_non_iana_extensions_size = sizeof(allowed_non_iana_extensions) / + sizeof(allowed_non_iana_extensions[0]); + + /* see: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */ + if (extension_id > 59 && extension_id != 65281) + { + u_int8_t extension_found = 0; + for (size_t i = 0; i < allowed_non_iana_extensions_size; ++i) + { + if (allowed_non_iana_extensions[i] == extension_id) + { + extension_found = 1; + break; + } + } + if (extension_found == 0) + { +#ifdef DEBUG_TLS + printf("[TLS] suspicious extension id: %u\n", extension_id); +#endif + ndpi_set_risk(flow, NDPI_TLS_EXTENSION_SUSPICIOUS); + return; + } + } + + /* Check for DTLS-only extensions. */ + if (is_dtls == 0) + { + if (extension_id == 53 || extension_id == 54) + { +#ifdef DEBUG_TLS + printf("[TLS] suspicious DTLS-only extension id: %u\n", extension_id); +#endif + ndpi_set_risk(flow, NDPI_TLS_EXTENSION_SUSPICIOUS); + return; + } + } +} + +/* **************************************** */ + int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, uint32_t quic_version) { struct ndpi_packet_struct *packet = &flow->packet; @@ -1274,6 +1330,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, printf("TLS [server][extension_id: %u/0x%04X][len: %u]\n", extension_id, extension_id, extension_len); #endif + checkExtensions(flow, is_dtls, extension_id, extension_len, offset + 4); if(extension_id == 43 /* supported versions */) { if(extension_len >= 2) { @@ -1604,6 +1661,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #ifdef DEBUG_TLS printf("Client TLS [extension_id: %u][extension_len: %u]\n", extension_id, extension_len); #endif + checkExtensions(flow, is_dtls, extension_id, extension_len, offset + extension_offset); if((extension_id == 0) || (packet->payload[extn_off] != packet->payload[extn_off+1])) { /* Skip GREASE */ @@ -1641,6 +1699,11 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #ifdef DEBUG_TLS printf("[TLS] SNI: [%s]\n", buffer); #endif + if (ndpi_is_printable_string(buffer, len) == 0) + { + ndpi_set_risk(flow, NDPI_TLS_EXTENSION_SUSPICIOUS); + } + if(!is_quic) { if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, buffer, strlen(buffer))) flow->l4.tcp.tls.subprotocol_detected = 1; |