Skip to content

Commit

Permalink
Add (kind of) support for loading a list of JA4C malicious fingerprints
Browse files Browse the repository at this point in the history
It might be usefull to be able to match traffic against a list of
suspicious JA4C fingerprints

Use the same code/logic/infrastructure used for JA3C (note that we are
going to remove JA3C...)

See: #2551
  • Loading branch information
IvanNardi committed Jan 13, 2025
1 parent 243b795 commit 0018ce6
Show file tree
Hide file tree
Showing 27 changed files with 179 additions and 278 deletions.
108 changes: 0 additions & 108 deletions example/ja3_fingerprints.csv

This file was deleted.

9 changes: 9 additions & 0 deletions example/ja4_fingerprints.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
################################################################
# List of malicious/suspicious JA4C fingerprints #
# #
# This is only an example. You can extend this list, putting #
# one fingeprint per row #
################################################################
#
# ja4c,comment
t13d1517h2_8daaf6152771_b0da82dd1658,this_is_not_a_real_malicious_fingerprint!!!!!
10 changes: 5 additions & 5 deletions example/ndpiReader.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ static char *results_path = NULL;
static char * bpfFilter = NULL; /**< bpf filter */
static char *_protoFilePath = NULL; /**< Protocol file path */
static char *_customCategoryFilePath= NULL; /**< Custom categories file path */
static char *_maliciousJA3Path = NULL; /**< Malicious JA3 signatures */
static char *_maliciousJA4Path = NULL; /**< Malicious JA4 signatures */
static char *_maliciousSHA1Path = NULL; /**< Malicious SSL certificate SHA1 fingerprints */
static char *_riskyDomainFilePath = NULL; /**< Risky domain files */
static char *_domain_suffixes = NULL; /**< Domain suffixes file */
Expand Down Expand Up @@ -684,7 +684,7 @@ static void help(u_int long_help) {
" -E <path> | Write flow fingerprints on the specified file\n"
" -r <path> | Load risky domain file\n"
" -R | Print detected realtime protocols\n"
" -j <path> | Load malicious JA3 fingeprints\n"
" -j <path> | Load malicious JA4 fingeprints\n"
" -S <path> | Load malicious SSL certificate SHA1 fingerprints\n"
" -G <dir> | Bind domain names to categories loading files from <dir>\n"
" -w <path> | Write test output on the specified file. This is useful for\n"
Expand Down Expand Up @@ -1157,7 +1157,7 @@ static void parse_parameters(int argc, char **argv)
break;

case 'j':
_maliciousJA3Path = optarg;
_maliciousJA4Path = optarg;
break;

case 'S':
Expand Down Expand Up @@ -2974,8 +2974,8 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle,
if(_riskyDomainFilePath)
ndpi_load_risk_domain_file(ndpi_thread_info[thread_id].workflow->ndpi_struct, _riskyDomainFilePath);

if(_maliciousJA3Path)
ndpi_load_malicious_ja3_file(ndpi_thread_info[thread_id].workflow->ndpi_struct, _maliciousJA3Path);
if(_maliciousJA4Path)
ndpi_load_malicious_ja4_file(ndpi_thread_info[thread_id].workflow->ndpi_struct, _maliciousJA4Path);

if(_maliciousSHA1Path)
ndpi_load_malicious_sha1_file(ndpi_thread_info[thread_id].workflow->ndpi_struct, _maliciousSHA1Path);
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_common_code.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void fuzz_init_detection_module(struct ndpi_detection_module_struct **ndpi_info_
ndpi_load_protocols_file(*ndpi_info_mod, "protos.txt");
ndpi_load_categories_file(*ndpi_info_mod, "categories.txt", NULL);
ndpi_load_risk_domain_file(*ndpi_info_mod, "risky_domains.txt");
ndpi_load_malicious_ja3_file(*ndpi_info_mod, "ja3_fingerprints.csv");
ndpi_load_malicious_ja4_file(*ndpi_info_mod, "ja4_fingerprints.csv");
ndpi_load_malicious_sha1_file(*ndpi_info_mod, "sha1_fingerprints.csv");

ndpi_set_config(*ndpi_info_mod, NULL, "filename.config", "config.txt");
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzz_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(fuzzed_data.ConsumeBool())
ndpi_load_risk_domain_file(ndpi_info_mod, fuzzed_data.ConsumeBool() ? NULL : "invalid_filename"); /* Error */
if(fuzzed_data.ConsumeBool())
ndpi_load_malicious_ja3_file(ndpi_info_mod, "ja3_fingerprints.csv");
ndpi_load_malicious_ja4_file(ndpi_info_mod, "ja4_fingerprints.csv");
if(fuzzed_data.ConsumeBool())
ndpi_load_malicious_ja3_file(ndpi_info_mod, fuzzed_data.ConsumeBool() ? NULL : "invalid_filename"); /* Error */
ndpi_load_malicious_ja4_file(ndpi_info_mod, fuzzed_data.ConsumeBool() ? NULL : "invalid_filename"); /* Error */
if(fuzzed_data.ConsumeBool())
ndpi_load_malicious_sha1_file(ndpi_info_mod, "sha1_fingerprints.csv");
if(fuzzed_data.ConsumeBool())
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_filecfg_malicious_ja3.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_set_config(ndpi_struct, "all", "log", "1");

fd = buffer_to_file(data, size);
load_malicious_ja3_file_fd(ndpi_struct, fd);
load_malicious_ja4_file_fd(ndpi_struct, fd);
if(fd)
fclose(fd);

Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_ndpi_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
ndpi_load_protocols_file(workflow->ndpi_struct, "protos.txt");
ndpi_load_categories_file(workflow->ndpi_struct, "categories.txt", NULL);
ndpi_load_risk_domain_file(workflow->ndpi_struct, "risky_domains.txt");
ndpi_load_malicious_ja3_file(workflow->ndpi_struct, "ja3_fingerprints.csv");
ndpi_load_malicious_ja4_file(workflow->ndpi_struct, "ja4_fingerprints.csv");
ndpi_load_malicious_sha1_file(workflow->ndpi_struct, "sha1_fingerprints.csv");

// enable all protocols
Expand Down
2 changes: 1 addition & 1 deletion src/include/ndpi_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ extern "C" {
* @return 0 if the file is loaded correctly;
* -1 else
*/
int ndpi_load_malicious_ja3_file(struct ndpi_detection_module_struct *ndpi_str, const char *path);
int ndpi_load_malicious_ja4_file(struct ndpi_detection_module_struct *ndpi_str, const char *path);

/**
* Read a file and load the list of malicious SSL certificate SHA1 fingerprints.
Expand Down
4 changes: 2 additions & 2 deletions src/include/ndpi_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ struct ndpi_detection_module_struct {
* update automa_type above
*/

ndpi_str_hash *malicious_ja3_hashmap, *malicious_sha1_hashmap;
ndpi_str_hash *malicious_ja4_hashmap, *malicious_sha1_hashmap;

ndpi_list *trusted_issuer_dn;

Expand Down Expand Up @@ -633,7 +633,7 @@ ndpi_risk_enum ndpi_network_risk_ptree_match(struct ndpi_detection_module_struct
int load_protocols_file_fd(struct ndpi_detection_module_struct *ndpi_mod, FILE *fd);
int load_categories_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd, void *user_data);
int load_malicious_sha1_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd);
int load_malicious_ja3_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd);
int load_malicious_ja4_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd);
int load_risk_domain_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd);
int load_config_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd);
int load_category_file_fd(struct ndpi_detection_module_struct *ndpi_str,
Expand Down
20 changes: 10 additions & 10 deletions src/lib/ndpi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3463,7 +3463,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(struct ndpi_glob
return(NULL);
}

ndpi_str->malicious_ja3_hashmap = NULL; /* Initialized on demand */
ndpi_str->malicious_ja4_hashmap = NULL; /* Initialized on demand */
ndpi_str->malicious_sha1_hashmap = NULL; /* Initialized on demand */
ndpi_str->risky_domain_automa.ac_automa = NULL; /* Initialized on demand */
ndpi_str->trusted_issuer_dn = NULL;
Expand Down Expand Up @@ -4314,8 +4314,8 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) {
if(ndpi_str->tls_cert_subject_automa.ac_automa != NULL)
ac_automata_release((AC_AUTOMATA_t *) ndpi_str->tls_cert_subject_automa.ac_automa, 0);

if(ndpi_str->malicious_ja3_hashmap != NULL)
ndpi_hash_free(&ndpi_str->malicious_ja3_hashmap);
if(ndpi_str->malicious_ja4_hashmap != NULL)
ndpi_hash_free(&ndpi_str->malicious_ja4_hashmap);

if(ndpi_str->malicious_sha1_hashmap != NULL)
ndpi_hash_free(&ndpi_str->malicious_sha1_hashmap);
Expand Down Expand Up @@ -5270,7 +5270,7 @@ int load_risk_domain_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE
* <ja3 hash>[,<other info>]
*
*/
int ndpi_load_malicious_ja3_file(struct ndpi_detection_module_struct *ndpi_str, const char *path) {
int ndpi_load_malicious_ja4_file(struct ndpi_detection_module_struct *ndpi_str, const char *path) {
int rc;
FILE *fd;

Expand All @@ -5283,7 +5283,7 @@ int ndpi_load_malicious_ja3_file(struct ndpi_detection_module_struct *ndpi_str,
return -1;
}

rc = load_malicious_ja3_file_fd(ndpi_str, fd);
rc = load_malicious_ja4_file_fd(ndpi_str, fd);

fclose(fd);

Expand All @@ -5292,13 +5292,13 @@ int ndpi_load_malicious_ja3_file(struct ndpi_detection_module_struct *ndpi_str,

/* ******************************************************************** */

int load_malicious_ja3_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd) {
int load_malicious_ja4_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd) {
char buffer[128], *line;
int len, num = 0;

if(!ndpi_str || !fd)
return(-1);
if(ndpi_str->malicious_ja3_hashmap == NULL && ndpi_hash_init(&ndpi_str->malicious_ja3_hashmap) != 0)
if(ndpi_str->malicious_ja4_hashmap == NULL && ndpi_hash_init(&ndpi_str->malicious_ja4_hashmap) != 0)
return(-1);

while(1) {
Expand All @@ -5321,12 +5321,12 @@ int load_malicious_ja3_file_fd(struct ndpi_detection_module_struct *ndpi_str, FI

len = strlen(line);

if(len != 32 /* size of MD5 hash */) {
NDPI_LOG_ERR(ndpi_str, "Not a JA3 md5 hash: [%s]\n", line);
if(len != 36 /* size of JA4C */) {
NDPI_LOG_ERR(ndpi_str, "Not a JA4C: [%s]\n", line);
continue;
}

if(ndpi_hash_add_entry(&ndpi_str->malicious_ja3_hashmap, line, len, 0) == 0)
if(ndpi_hash_add_entry(&ndpi_str->malicious_ja4_hashmap, line, len, 0) == 0)
num++;
}

Expand Down
20 changes: 10 additions & 10 deletions src/lib/protocols/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3247,20 +3247,20 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_JA
printf("[JA3] Client: %s \n", flow->protos.tls_quic.ja3_client);
#endif

if(ndpi_struct->malicious_ja3_hashmap != NULL) {
u_int16_t rc1 = ndpi_hash_find_entry(ndpi_struct->malicious_ja3_hashmap,
flow->protos.tls_quic.ja3_client,
NDPI_ARRAY_LENGTH(flow->protos.tls_quic.ja3_client) - 1,
NULL);

if(rc1 == 0)
ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_FINGERPRINT, flow->protos.tls_quic.ja3_client);
}
}

if(ndpi_struct->cfg.tls_ja4c_fingerprint_enabled) {
ndpi_compute_ja4(ndpi_struct, flow, quic_version, &ja);

if(ndpi_struct->malicious_ja4_hashmap != NULL) {
u_int16_t rc1 = ndpi_hash_find_entry(ndpi_struct->malicious_ja4_hashmap,
flow->protos.tls_quic.ja4_client,
NDPI_ARRAY_LENGTH(flow->protos.tls_quic.ja4_client) - 1,
NULL);

if(rc1 == 0)
ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_FINGERPRINT, flow->protos.tls_quic.ja4_client);
}
}
/* End JA3/JA4 */
}
Expand Down
Loading

0 comments on commit 0018ce6

Please sign in to comment.