aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2019-05-20 22:02:21 +0200
committerLuca Deri <deri@ntop.org>2019-05-20 22:02:21 +0200
commit0d2f8f4498f3158be31582c04db0935746a45dd4 (patch)
tree8eb0b915a2e83c9393708f206b1990a3610a6e59
parent53e64df8e2470c1b5d397e3ab183091693f7daf7 (diff)
Implements #705
-rw-r--r--example/ndpiReader.c34
-rw-r--r--example/ndpi_util.c4
-rw-r--r--example/ndpi_util.h1
-rw-r--r--src/include/ndpi_typedefs.h1
-rw-r--r--src/lib/ndpi_main.c2
-rw-r--r--src/lib/protocols/ssl.c83
6 files changed, 104 insertions, 21 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 216b4d9ab..ec9f22d15 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -749,6 +749,22 @@ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) {
/* ********************************** */
+static char* print_cipher(u_int8_t c) {
+ switch(c) {
+ case NDPI_CIPHER_INSECURE:
+ return(" (INSECURE)");
+ break;
+
+ case NDPI_CIPHER_WEAK:
+ return(" (WEAK)");
+ break;
+
+ default:
+ return("");
+ }
+}
+/* ********************************** */
+
/**
* @brief Print the flow
*/
@@ -800,14 +816,16 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
flow->dst2src_packets, (long long unsigned int) flow->dst2src_bytes);
if(flow->host_server_name[0] != '\0') fprintf(out, "[Host: %s]", flow->host_server_name);
-
+
if(flow->info[0] != '\0') fprintf(out, "[%s]", flow->info);
-
- if(flow->ssh_ssl.ja3_client[0] != '\0') fprintf(out, "[JA3C: %s]", flow->ssh_ssl.ja3_client);
+
+ if(flow->ssh_ssl.ja3_client[0] != '\0') fprintf(out, "[JA3C: %s%s]", flow->ssh_ssl.ja3_client,
+ print_cipher(flow->ssh_ssl.client_unsafe_cipher));
if(flow->ssh_ssl.server_info[0] != '\0') fprintf(out, "[server: %s]", flow->ssh_ssl.server_info);
-
- if(flow->ssh_ssl.ja3_server[0] != '\0') fprintf(out, "[JA3S: %s]", flow->ssh_ssl.ja3_server);
+
+ if(flow->ssh_ssl.ja3_server[0] != '\0') fprintf(out, "[JA3S: %s%s]", flow->ssh_ssl.ja3_server,
+ print_cipher(flow->ssh_ssl.server_unsafe_cipher));
if(flow->ssh_ssl.server_organization[0] != '\0') fprintf(out, "[organization: %s]", flow->ssh_ssl.server_organization);
if(flow->bittorent_hash[0] != '\0') fprintf(out, "[BT Hash: %s]", flow->bittorent_hash);
@@ -856,13 +874,13 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if(flow->ssh_ssl.ja3_server[0] != '\0')
json_object_object_add(jObj,"ja3s",json_object_new_string(flow->ssh_ssl.ja3_server));
-
+
if(flow->ssh_ssl.ja3_client[0] != '\0')
json_object_object_add(jObj,"ja3c",json_object_new_string(flow->ssh_ssl.ja3_client));
-
+
if(flow->ja3_server[0] != '\0')
json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ja3_server));
-
+
if(flow->ssh_ssl.client_info[0] != '\0')
json_object_object_add(sjObj, "client", json_object_new_string(flow->ssh_ssl.client_info));
diff --git a/example/ndpi_util.c b/example/ndpi_util.c
index da7a87bdb..92d8dca80 100644
--- a/example/ndpi_util.c
+++ b/example/ndpi_util.c
@@ -572,6 +572,8 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
flow->ndpi_flow->protos.stun_ssl.ssl.ja3_client);
snprintf(flow->ssh_ssl.ja3_server, sizeof(flow->ssh_ssl.ja3_server), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.ja3_server);
+ flow->ssh_ssl.client_unsafe_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.client_unsafe_cipher;
+ flow->ssh_ssl.server_unsafe_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.server_unsafe_cipher;
}
}
@@ -684,7 +686,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
/* New protocol detected or give up */
flow->detection_completed = 1;
/* Check if we should keep checking extra packets */
- if(ndpi_flow->check_extra_packets)
+ if(ndpi_flow && ndpi_flow->check_extra_packets)
flow->check_extra_packets = 1;
if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_UNKNOWN)
diff --git a/example/ndpi_util.h b/example/ndpi_util.h
index 57772455f..d5a46735c 100644
--- a/example/ndpi_util.h
+++ b/example/ndpi_util.h
@@ -99,6 +99,7 @@ typedef struct ndpi_flow_info {
struct {
char client_info[64], server_info[64], server_organization[64],
ja3_client[33], ja3_server[33];
+ u_int8_t client_unsafe_cipher:2, server_unsafe_cipher:2, _pad:4;
} ssh_ssl;
void *src_id, *dst_id;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 77f0e0e85..470e02fe0 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1093,6 +1093,7 @@ struct ndpi_flow_struct {
struct {
char client_certificate[64], server_certificate[64], server_organization[64];
char ja3_client[33], ja3_server[33];
+ u_int8_t client_unsafe_cipher:2, server_unsafe_cipher:2, _pad:4;
} ssl;
struct {
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 737124697..fc898d4b8 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -6404,3 +6404,5 @@ int ndpi_flowv6_flow_hash(u_int8_t l4_proto, struct ndpi_in6_addr *src_ip, struc
return(0); /* OK */
}
+
+/* **************************************** */
diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/ssl.c
index e80d5deee..19725e518 100644
--- a/src/lib/protocols/ssl.c
+++ b/src/lib/protocols/ssl.c
@@ -43,6 +43,8 @@ typedef struct MD5Context {
unsigned char in[64];
} MD5_CTX;
+/* **************************************** */
+
static int is_big_endian(void) {
static const int n = 1;
return ((char *) &n)[0] == 0;
@@ -352,6 +354,58 @@ struct ja3_info {
u_int8_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA3];
};
+/* **************************************** */
+
+struct cipher_weakness {
+ u_int16_t cipher_id;
+ u_int8_t weakness_type;
+};
+
+static struct cipher_weakness safe_ssl_ciphers[] =
+ {
+ /* https://community.qualys.com/thread/18212-how-does-qualys-determine-the-server-cipher-suites */
+ /* INSECURE */
+ { 0xc011, NDPI_CIPHER_INSECURE }, /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
+ { 0x0005, NDPI_CIPHER_INSECURE }, /* TLS_RSA_WITH_RC4_128_SHA */
+ { 0x0004, NDPI_CIPHER_INSECURE }, /* TLS_RSA_WITH_RC4_128_MD5 */
+ /* WEAK */
+ { 0x009d, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_256_GCM_SHA384 */
+ { 0x003d, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_256_CBC_SHA256 */
+ { 0x0035, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_256_CBC_SHA */
+ { 0x0084, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA */
+ { 0x009c, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_128_GCM_SHA256 */
+ { 0x003c, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_128_CBC_SHA256 */
+ { 0x002f, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_AES_128_CBC_SHA */
+ { 0x0041, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA */
+ { 0xc012, NDPI_CIPHER_WEAK }, /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */
+ { 0x0016, NDPI_CIPHER_WEAK }, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */
+ { 0x000a, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */
+ { 0x0096, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_SEED_CBC_SHA */
+ { 0x0007, NDPI_CIPHER_WEAK }, /* TLS_RSA_WITH_IDEA_CBC_SHA */
+
+ { 0x0, NDPI_CIPHER_SAFE } /* END */
+};
+
+static u_int8_t is_safe_ssl_cipher(u_int16_t cipher) {
+ u_int i;
+
+ for(i=0; safe_ssl_ciphers[i].cipher_id != 0; i++) {
+ if(safe_ssl_ciphers[i].cipher_id == cipher) {
+#ifdef CERTIFICATE_DEBUG
+ printf("%s %s(%04X / %u)\n",
+ (safe_ssl_ciphers[i].weakness_type == NDPI_CIPHER_WEAK) ? "WEAK" : "INSECURE",
+ __FUNCTION__, cipher, cipher);
+#endif
+
+ return(safe_ssl_ciphers[i].weakness_type);
+ }
+ }
+
+ return(NDPI_CIPHER_SAFE); /* We're safe */
+}
+/* **************************************** */
+
+
/* code fixes courtesy of Alexsandro Brahm <alex@digistar.com.br> */
int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
@@ -410,6 +464,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
offset += session_id_len+1;
ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ flow->protos.stun_ssl.ssl.server_unsafe_cipher = is_safe_ssl_cipher(ja3.cipher[0]);
#ifdef CERTIFICATE_DEBUG
printf("SSL [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]);
@@ -539,21 +594,21 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
ja3.ssl_version = ssl_version;
if((session_id_len+base_offset+2) <= total_len) {
- u_int16_t cypher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
- u_int16_t i, cypher_offset = base_offset + session_id_len + 3;
+ u_int16_t cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
+ u_int16_t i, cipher_offset = base_offset + session_id_len + 3;
#ifdef CERTIFICATE_DEBUG
- printf("Client SSL [client cypher_len: %u]\n", cypher_len);
+ printf("Client SSL [client cipher_len: %u]\n", cipher_len);
#endif
- if((cypher_offset+cypher_len) <= total_len) {
- for(i=0; i<cypher_len;) {
- u_int16_t *id = (u_int16_t*)&packet->payload[cypher_offset+i];
+ if((cipher_offset+cipher_len) <= total_len) {
+ for(i=0; i<cipher_len;) {
+ u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
#ifdef CERTIFICATE_DEBUG
- printf("Client SSL [cypher suite: %u] [%u/%u]\n", ntohs(*id), i, cypher_len);
+ printf("Client SSL [cipher suite: %u] [%u/%u]\n", ntohs(*id), i, cipher_len);
#endif
- if((*id == 0) || (packet->payload[cypher_offset+i] != packet->payload[cypher_offset+i+1])) {
+ if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) {
/*
Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html]
https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
@@ -564,7 +619,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
else {
invalid_ja3 = 1;
#ifdef CERTIFICATE_DEBUG
- printf("Client SSL Invalid cypher %u\n", ja3.num_cipher);
+ printf("Client SSL Invalid cipher %u\n", ja3.num_cipher);
#endif
}
}
@@ -574,11 +629,11 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
} else {
invalid_ja3 = 1;
#ifdef CERTIFICATE_DEBUG
- printf("Client SSL Invalid len %u vs %u\n", (cypher_offset+cypher_len), total_len);
+ printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len);
#endif
}
- offset = base_offset + session_id_len + cypher_len + 2;
+ offset = base_offset + session_id_len + cipher_len + 2;
flow->l4.tcp.ssl_seen_client_cert = 1;
@@ -726,9 +781,13 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
if(!invalid_ja3) {
ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version);
- for(i=0; i<ja3.num_cipher; i++)
+ for(i=0; i<ja3.num_cipher; i++) {
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
(i > 0) ? "-" : "", ja3.cipher[i]);
+
+ if(flow->protos.stun_ssl.ssl.client_unsafe_cipher < NDPI_CIPHER_INSECURE)
+ flow->protos.stun_ssl.ssl.client_unsafe_cipher = is_safe_ssl_cipher(ja3.cipher[i]);
+ }
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");