aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorToni <matzeton@googlemail.com>2021-07-19 16:23:24 +0200
committerGitHub <noreply@github.com>2021-07-19 16:23:24 +0200
commit32275543c421eae55fd98a5a98e00059a0407953 (patch)
tree758cb9fdcb089880248cbb8e6f86f1482eb0099b /src/lib
parent57b8969a3d30cfdefe54fc46f4d5552d76bd1b82 (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.c1
-rw-r--r--src/lib/ndpi_utils.c48
-rw-r--r--src/lib/protocols/tls.c99
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;