aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca <deri@ntop.org>2021-05-06 21:42:06 +0200
committerLuca <deri@ntop.org>2021-05-06 21:42:06 +0200
commitae2470fad40d1865c6fd17f686f43555cc47b92b (patch)
tree520bd1e9f7892418a32fe842b8d1777565f5ce8f
parent808050e6357f0c84826828f1922ac1a29803845b (diff)
Initial work towards detection via TLS of browser types
-rw-r--r--example/ndpiReader.c5
-rw-r--r--example/reader_util.c2
-rw-r--r--example/reader_util.h3
-rw-r--r--src/include/ndpi_typedefs.h71
-rw-r--r--src/lib/protocols/tls.c60
5 files changed, 100 insertions, 41 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 806fb4a69..1736b4fa3 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -1474,6 +1474,11 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
}
}
+#ifdef EURISTICS_CODE
+ if(flow->ssh_tls.browser_euristics.is_safari_tls) fprintf(out, "[Safari]");
+ if(flow->ssh_tls.browser_euristics.is_firefox_tls) fprintf(out, "[Firefox]");
+#endif
+
if(flow->ssh_tls.notBefore && flow->ssh_tls.notAfter) {
char notBefore[32], notAfter[32];
struct tm a, b;
diff --git a/example/reader_util.c b/example/reader_util.c
index af58d8db5..18c8c6e2a 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -1170,6 +1170,8 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
flow->ssh_tls.sha1_cert_fingerprint_set = 1;
}
+ flow->ssh_tls.browser_euristics = flow->ndpi_flow->protos.tls_quic_stun.tls_quic.browser_euristics;
+
if(flow->ndpi_flow->protos.tls_quic_stun.tls_quic.alpn) {
if((flow->ssh_tls.tls_alpn = ndpi_strdup(flow->ndpi_flow->protos.tls_quic_stun.tls_quic.alpn)) != NULL)
correct_csv_data_field(flow->ssh_tls.tls_alpn);
diff --git a/example/reader_util.h b/example/reader_util.h
index c54d68aa4..5175e868d 100644
--- a/example/reader_util.h
+++ b/example/reader_util.h
@@ -211,10 +211,13 @@ typedef struct ndpi_flow_info {
ja3_client[33], ja3_server[33],
sha1_cert_fingerprint[20];
u_int8_t sha1_cert_fingerprint_set;
+ struct tls_euristics browser_euristics;
+
struct {
u_int16_t cipher_suite;
char *esni;
} encrypted_sni;
+
time_t notBefore, notAfter;
u_int16_t server_cipher;
ndpi_cipher_weakness client_unsafe_cipher, server_unsafe_cipher;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 56927be53..4c0e4818e 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -65,7 +65,7 @@ typedef enum {
- nDPI/wireshark/ndpi.lua
- ndpi_risk2str and ndpi_risk2severity (in ndpi_utils.c)
- https://github.com/ntop/ntopng/blob/dev/scripts/lua/modules/flow_risk_utils.lua
- - ndpi_risk_enum (in python/ndpi.py)
+ - ndpi_risk_enum (in python/ndpi.py)
*/
typedef enum {
NDPI_NO_RISK = 0,
@@ -113,7 +113,7 @@ typedef enum {
NDPI_RISK_HIGH,
NDPI_RISK_SEVERE
} ndpi_risk_severity;
-
+
/* NDPI_VISIT */
typedef enum {
ndpi_preorder,
@@ -506,8 +506,8 @@ PACK_ON struct tinc_cache_entry {
u_int16_t dst_port;
} PACK_OFF;
-/*
- In case the typedef below is modified, please update
+/*
+ In case the typedef below is modified, please update
ndpi_http_method2str (ndpi_utils.c)
*/
typedef enum {
@@ -527,7 +527,7 @@ struct ndpi_lru_cache_entry {
u_int32_t key; /* Store the whole key to avoid ambiguities */
u_int32_t is_full:1, value:16, pad:15;
};
-
+
struct ndpi_lru_cache {
u_int32_t num_entries;
struct ndpi_lru_cache_entry *entries;
@@ -695,16 +695,16 @@ struct ndpi_flow_tcp_struct {
struct {
message_t message;
-
+
void* srv_cert_fingerprint_ctx; /* SHA-1 */
-
+
/* NDPI_PROTOCOL_TLS */
u_int8_t hello_processed:1, certificate_processed:1, subprotocol_detected:1,
fingerprint_set:1, _pad:4;
u_int8_t num_tls_blocks;
int16_t tls_application_blocks_len[NDPI_MAX_NUM_TLS_APPL_BLOCKS]; /* + = src->dst, - = dst->src */
} tls;
-
+
/* NDPI_PROTOCOL_POSTGRES */
u_int32_t postgres_stage:3;
@@ -965,7 +965,7 @@ typedef enum {
NDPI_PROTOCOL_CATEGORY_SHOPPING,
NDPI_PROTOCOL_CATEGORY_PRODUCTIVITY,
NDPI_PROTOCOL_CATEGORY_FILE_SHARING,
- /*
+ /*
The category below is used by sites who are used
to test connectivity
*/
@@ -1081,7 +1081,7 @@ struct ndpi_detection_module_struct {
u_int32_t ticks_per_second;
u_int16_t num_tls_blocks_to_follow;
u_int8_t skip_tls_blocks_until_change_cipher:1, enable_ja3_plus:1, _notused:6;
-
+
#ifdef NDPI_ENABLE_DEBUG_MESSAGES
void *user_data;
#endif
@@ -1134,7 +1134,7 @@ struct ndpi_detection_module_struct {
risky_domain_automa, tls_cert_subject_automa,
malicious_ja3_automa, malicious_sha1_automa;
/* IMPORTANT: please update ndpi_finalize_initialization() whenever you add a new automa */
-
+
struct {
ndpi_automa hostnames, hostnames_shadow;
void *ipAddresses, *ipAddresses_shadow; /* Patricia */
@@ -1181,7 +1181,7 @@ struct ndpi_detection_module_struct {
/* NDPI_PROTOCOL_MINING and subprotocols */
struct ndpi_lru_cache *mining_cache;
-
+
/* NDPI_PROTOCOL_MSTEAMS */
struct ndpi_lru_cache *msteams_cache;
@@ -1190,7 +1190,7 @@ struct ndpi_detection_module_struct {
u_int8_t direction_detect_disable:1, /* disable internal detection of packet direction */ _pad:7;
void (*ndpi_notify_lru_add_handler_ptr)(ndpi_lru_cache_type cache_type, u_int32_t proto, u_int32_t app_proto);
-
+
#ifdef CUSTOM_NDPI_PROTOCOLS
#include "../../../nDPI-custom/custom_ndpi_typedefs.h"
#endif
@@ -1211,6 +1211,14 @@ typedef enum {
#define MAX_NUM_TLS_SIGNATURE_ALGORITHMS 16
+struct tls_euristics {
+ /*
+ TLS euristics for detecting browsers usage
+ NOTE: expect false positives
+ */
+ u_int8_t is_safari_tls:1, is_firefox_tls:1, notused:6;
+};
+
/*
NOTE
When the struct below is modified don't forget to update
@@ -1258,7 +1266,7 @@ struct ndpi_flow_struct {
/* Place textual flow info here */
char flow_extra_info[16];
-
+
/*
Pointer to src or dst that identifies the
server of this connection
@@ -1269,7 +1277,7 @@ struct ndpi_flow_struct {
u_int8_t initial_binary_bytes[8], initial_binary_bytes_len;
u_int8_t risk_checked;
ndpi_risk risk; /* Issues found with this flow [bitmask of ndpi_risk] */
-
+
/*
This structure below will not not stay inside the protos
structure below as HTTP is used by many subprotocols
@@ -1286,12 +1294,12 @@ struct ndpi_flow_struct {
u_char detected_os[32]; /* Via HTTP/QUIC User-Agent */
} http;
- /*
+ /*
Put outside of the union to avoid issues in case the protocol
is remapped to somethign pther than Kerberos due to a faulty
dissector
*/
- struct {
+ struct {
char *pktbuf;
u_int16_t pktbuf_maxlen, pktbuf_currlen;
} kerberos_buf;
@@ -1321,10 +1329,17 @@ struct ndpi_flow_struct {
*server_names, *alpn, *tls_supported_versions, *issuerDN, *subjectDN;
u_int32_t notBefore, notAfter;
char ja3_client[33], ja3_server[33];
- u_int16_t server_cipher;
+ u_int16_t server_cipher;
+ u_int8_t sha1_certificate_fingerprint[20];
+
+#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS
+ /* Under #ifdef to save memory for those who do not need them */
+ u_int8_t num_tls_signature_algorithms;
u_int16_t client_signature_algorithms[MAX_NUM_TLS_SIGNATURE_ALGORITHMS];
- u_int8_t num_tls_signature_algorithms, sha1_certificate_fingerprint[20];
-
+#endif
+
+ struct tls_euristics browser_euristics;
+
struct {
u_int16_t cipher_suite;
char *esni;
@@ -1348,7 +1363,7 @@ struct ndpi_flow_struct {
struct {
u_int8_t last_one_byte_pkt, last_byte;
} imo;
-
+
struct {
u_int8_t username_detected:1, username_found:1,
password_detected:1, password_found:1,
@@ -1356,7 +1371,7 @@ struct ndpi_flow_struct {
u_int8_t character_id;
char username[32], password[32];
} telnet;
-
+
struct {
char version[32];
} ubntac2;
@@ -1370,7 +1385,7 @@ struct ndpi_flow_struct {
u_int8_t auth_found:1, auth_failed:1, _pad:5;
char username[16], password[16];
} ftp_imap_pop_smtp;
-
+
struct {
/* Bittorrent hash */
u_char hash[20];
@@ -1451,7 +1466,7 @@ struct ndpi_flow_struct {
/* NDPI_PROTOCOL_CSGO */
u_int8_t csgo_strid[18],csgo_state,csgo_s2;
u_int32_t csgo_id2;
-
+
/* internal structures to save functions calls */
struct ndpi_packet_struct packet;
struct ndpi_flow_struct *flow;
@@ -1505,7 +1520,7 @@ typedef enum {
ndpi_serialization_format_csv
} ndpi_serialization_format;
-/* Note:
+/* Note:
* - up to 16 types (TLV encoding: "4 bit key type" << 4 | "4 bit value type")
* - key supports string and uint32 (compressed to uint8/uint16) only, this is also enforced by the API */
typedef enum {
@@ -1627,7 +1642,7 @@ typedef struct ndpi_ptree ndpi_ptree_t;
/* **************************************** */
struct ndpi_hll {
- u_int8_t bits;
+ u_int8_t bits;
size_t size;
u_int8_t *registers;
};
@@ -1643,7 +1658,7 @@ enum ndpi_bin_family {
struct ndpi_bin {
u_int8_t num_bins, is_empty;
enum ndpi_bin_family family;
-
+
union {
u_int8_t *bins8; /* num_bins bins */
u_int16_t *bins16; /* num_bins bins */
@@ -1685,7 +1700,7 @@ struct ndpi_hw_struct {
u_int32_t num_values;
double u, v, sum_square_error;
-
+
/* These two values need to store the signal history */
u_int32_t *y;
double *s;
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 939564994..e4737829f 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -1158,7 +1158,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
int i, rc;
ja3.server.tls_handshake_version = tls_version;
-
+
#ifdef DEBUG_TLS
printf("TLS Server Hello [version: 0x%04X]\n", tls_version);
#endif
@@ -1312,7 +1312,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
printf("Server TLS Invalid len %u vs %u\n", s_offset+extension_len, total_len);
#endif
}
- }
+ }
i += 4 + extension_len, offset += 4 + extension_len;
} /* for */
@@ -1347,16 +1347,16 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",%s", ja3.server.alpn);
if((rc > 0) && (ja3_str_len + rc < JA3_STR_LEN)) ja3_str_len += rc;
}
-
+
#ifdef DEBUG_TLS
printf("[JA3+] Server: %s \n", ja3_str);
#endif
- } else {
+ } else {
#ifdef DEBUG_TLS
printf("[JA3] Server: %s \n", ja3_str);
#endif
}
-
+
ndpi_MD5Init(&ctx);
ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
ndpi_MD5Final(md5_hash, &ctx);
@@ -1377,7 +1377,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
flow->protos.tls_quic_stun.tls_quic.ssl_version = ja3.client.tls_handshake_version = tls_version;
if(flow->protos.tls_quic_stun.tls_quic.ssl_version < 0x0302) /* TLSv1.1 */
ndpi_set_risk(flow, NDPI_TLS_OBSOLETE_VERSION);
-
+
if((session_id_len+base_offset+3) > packet->payload_packet_len)
return(0); /* Not found */
@@ -1400,6 +1400,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
if((cipher_offset+cipher_len) <= total_len) {
+ u_int8_t safari_ciphers = 0;
+
for(i=0; i<cipher_len;) {
u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
@@ -1407,23 +1409,40 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
printf("Client TLS [cipher suite: %u/0x%04X] [%d/%u]\n", ntohs(*id), ntohs(*id), i, cipher_len);
#endif
if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) {
+ u_int16_t cipher_id = ntohs(*id);
/*
Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html]
https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
*/
if(ja3.client.num_cipher < MAX_NUM_JA3)
- ja3.client.cipher[ja3.client.num_cipher++] = ntohs(*id);
+ ja3.client.cipher[ja3.client.num_cipher++] = cipher_id;
else {
invalid_ja3 = 1;
#ifdef DEBUG_TLS
printf("Client TLS Invalid cipher %u\n", ja3.client.num_cipher);
#endif
}
+
+ switch(cipher_id) {
+ case 0x00c008: /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA */
+ case 0x00C023: /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 */
+ case 0x00C024: /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 */
+ case 0x00c012: /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */
+ case 0x00C027: /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 */
+ case 0x00C028: /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 */
+ case 0x00003C: /* TLS_RSA_WITH_AES_128_CBC_SHA256 */
+ case 0x00003D: /* TLS_RSA_WITH_AES_256_CBC_SHA256 */
+ safari_ciphers++;
+ break;
+ }
}
i += 2;
- }
+ } /* for */
+
+ if(safari_ciphers >= 6)
+ flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_safari_tls = 1;
} else {
invalid_ja3 = 1;
#ifdef DEBUG_TLS
@@ -1622,17 +1641,32 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
s_offset += 2;
tot_signature_algorithms_len = ndpi_min((sizeof(ja3.client.signature_algorithms) / 2) - 1, tot_signature_algorithms_len);
+#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS
+ flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms = ndpi_min(tot_signature_algorithms_len, MAX_NUM_TLS_SIGNATURE_ALGORITHMS);
+
+ memcpy(flow->protos.tls_quic_stun.tls_quic.client_signature_algorithms,
+ &packet->payload[s_offset], 2 /* 16 bit */*flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms);
+#endif
+
+
for(i=0; i<tot_signature_algorithms_len; i++) {
int rc = snprintf(&ja3.client.signature_algorithms[i*2], sizeof(ja3.client.signature_algorithms)-i*2, "%02X", packet->payload[s_offset+i]);
- if(flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms < MAX_NUM_TLS_SIGNATURE_ALGORITHMS) {
- if(flow->protos.tls_quic_stun.tls_quic.client_signature_algorithms[flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms])
- flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms++;
- }
-
if(rc < 0) break;
}
+ for(i=0; i<tot_signature_algorithms_len; i+=2) {
+ u_int16_t cipher_id = (u_int16_t)ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
+
+ // printf("=>> %04X\n", cipher_id);
+
+ if(cipher_id == 0x0603 /* ECDSA_SECP521R1_SHA512 */) {
+ flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_firefox_tls = 1;
+ break;
+ }
+ }
+
+
ja3.client.signature_algorithms[i*2] = '\0';
#ifdef DEBUG_TLS