diff options
author | Luca Deri <deri@ntop.org> | 2019-05-20 22:02:21 +0200 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2019-05-20 22:02:21 +0200 |
commit | 0d2f8f4498f3158be31582c04db0935746a45dd4 (patch) | |
tree | 8eb0b915a2e83c9393708f206b1990a3610a6e59 | |
parent | 53e64df8e2470c1b5d397e3ab183091693f7daf7 (diff) |
Implements #705
-rw-r--r-- | example/ndpiReader.c | 34 | ||||
-rw-r--r-- | example/ndpi_util.c | 4 | ||||
-rw-r--r-- | example/ndpi_util.h | 1 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 1 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/ssl.c | 83 |
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, ","); |