Add support for ja3 & ja3s

This commit is contained in:
William Robinet 2021-03-24 17:03:22 +01:00
parent 1c2bf72485
commit 15ad7190fb
2 changed files with 242 additions and 3 deletions

View file

@ -1,4 +1,5 @@
#include <json-c/json.h> #include <json-c/json.h>
#include <openssl/md5.h>
#include "network.h" #include "network.h"
#include "ssl_h.h" #include "ssl_h.h"
#include "sslprint.h" #include "sslprint.h"
@ -191,7 +192,6 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
segment *seg; segment *seg;
Data *data; Data *data;
{ {
struct json_object *jobj; struct json_object *jobj;
jobj = ssl->cur_json_st; jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ClientHello")); json_object_object_add(jobj, "handshake_type", json_object_new_string("ClientHello"));
@ -199,6 +199,16 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
UINT4 vj,vn,cs,cslen,complen,comp,odd,exlen,ex; UINT4 vj,vn,cs,cslen,complen,comp,odd,exlen,ex;
Data session_id,random; Data session_id,random;
int r; int r;
char *ja3_fp = NULL;
char *ja3_str = NULL;
char *ja3_ver_str = NULL;
char *ja3_cs_str = NULL;
char *ja3_ex_str = NULL;
char *ja3_ec_str = NULL;
char *ja3_ecp_str = NULL;
ssl->cur_ja3_ec_str = NULL;
ssl->cur_ja3_ecp_str = NULL;
extern decoder cipher_suite_decoder[]; extern decoder cipher_suite_decoder[];
extern decoder compression_method_decoder[]; extern decoder compression_method_decoder[];
@ -209,6 +219,9 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vj);
SSL_DECODE_UINT8(ssl,0,0,data,&vn); SSL_DECODE_UINT8(ssl,0,0,data,&vn);
ja3_ver_str = calloc(7,sizeof(char));
snprintf(ja3_ver_str, 7, "%u", ((vj & 0xff) << 8) | (vn & 0xff));
P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn); P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn);
LF; LF;
} }
@ -242,8 +255,16 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
0,data,&cs)) 0,data,&cs))
return(1); return(1);
ssl_print_cipher_suite(ssl,(vj<<8)|vn,P_HL,cs); ssl_print_cipher_suite(ssl,(vj<<8)|vn,P_HL,cs);
if(!ja3_cs_str)
ja3_cs_str = calloc(7, 1);
else
ja3_cs_str = realloc(ja3_cs_str, strlen(ja3_cs_str) + 7);
snprintf(ja3_cs_str + strlen(ja3_cs_str), 7, "%u-", cs);
LF; LF;
} }
if(ja3_cs_str && ja3_cs_str[strlen(ja3_cs_str) - 1] == '-')
ja3_cs_str[strlen(ja3_cs_str) - 1] = '\0';
} }
SSL_DECODE_UINT8(ssl,"compressionMethod len",0,data,&complen); SSL_DECODE_UINT8(ssl,"compressionMethod len",0,data,&complen);
@ -260,6 +281,13 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
explain(ssl , "extensions\n"); explain(ssl , "extensions\n");
while(data->len) { while(data->len) {
SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex);
if(!ja3_ex_str)
ja3_ex_str = calloc(7, 1);
else
ja3_ex_str = realloc(ja3_ex_str, strlen(ja3_ex_str) + 7);
snprintf(ja3_ex_str + strlen(ja3_ex_str), 7, "%u-", ex);
if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) {
decode_extension(ssl,dir,seg,data); decode_extension(ssl,dir,seg,data);
P_(P_RH){ P_(P_RH){
@ -269,7 +297,75 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
} }
LF; LF;
} }
if(ja3_ex_str && ja3_ex_str[strlen(ja3_ex_str) - 1] == '-')
ja3_ex_str[strlen(ja3_ex_str) - 1] = '\0';
} }
ja3_ec_str = ssl->cur_ja3_ec_str;
ja3_ecp_str = ssl->cur_ja3_ecp_str;
if(!ja3_ver_str) {
ja3_ver_str = calloc(1, 1);
*ja3_ver_str = '\0';
}
if(!ja3_cs_str) {
ja3_cs_str = calloc(1, 1);
*ja3_cs_str = '\0';
}
if(!ja3_ex_str) {
ja3_ex_str = calloc(1, 1);
*ja3_ex_str = '\0';
}
if(!ja3_ec_str) {
ja3_ec_str = calloc(1, 1);
*ja3_ec_str = '\0';
}
if(!ja3_ecp_str) {
ja3_ecp_str = calloc(1, 1);
*ja3_ecp_str = '\0';
}
int ja3_str_len =
strlen(ja3_ver_str) + 1
+ strlen(ja3_cs_str) + 1
+ strlen(ja3_ex_str) + 1
+ strlen(ja3_ec_str) + 1
+ strlen(ja3_ecp_str) + 1;
ja3_str = calloc(ja3_str_len, 1);
snprintf(ja3_str, ja3_str_len, "%s,%s,%s,%s,%s",
ja3_ver_str, ja3_cs_str, ja3_ex_str, ja3_ec_str, ja3_ecp_str);
MD5_CTX md5;
UCHAR tmp[16];
MD5_Init(&md5);
MD5_Update(&md5, ja3_str, ja3_str_len);
MD5_Final(tmp,&md5);
ja3_fp = calloc(33,1);
*ja3_fp = '\0';
for(int i=0; i<16; i++) {
snprintf(ja3_fp + strlen(ja3_fp), 3, "%02x", tmp[i]);
}
json_object_object_add(jobj, "ja3_str", json_object_new_string(ja3_str));
json_object_object_add(jobj, "ja3_fp", json_object_new_string(ja3_fp));
explain(ssl, "ja3 string: %s\n", ja3_str);
explain(ssl, "ja3 fingerprint: %s\n", ja3_fp);
free(ja3_fp);
free(ja3_str);
free(ja3_ver_str);
free(ja3_cs_str);
free(ja3_ex_str);
free(ja3_ec_str);
free(ja3_ecp_str);
return(0); return(0);
} }
@ -283,6 +379,12 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
int r; int r;
Data rnd,session_id; Data rnd,session_id;
UINT4 vj,vn,exlen,ex; UINT4 vj,vn,exlen,ex;
char *ja3s_fp = NULL;
char *ja3s_str = NULL;
char *ja3s_ver_str = NULL;
char *ja3s_c_str = NULL;
char *ja3s_ex_str = NULL;
extern decoder extension_decoder[]; extern decoder extension_decoder[];
@ -295,6 +397,9 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vj);
SSL_DECODE_UINT8(ssl,0,0,data,&vn); SSL_DECODE_UINT8(ssl,0,0,data,&vn);
ja3s_ver_str = calloc(7,sizeof(char));
snprintf(ja3s_ver_str, 7, "%u", ((vj & 0xff) << 8) | (vn & 0xff));
ssl->version=vj*256+vn; ssl->version=vj*256+vn;
P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn); P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn);
LF; LF;
@ -312,6 +417,9 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
} }
ssl_find_cipher(ssl->cipher_suite,&ssl->cs); ssl_find_cipher(ssl->cipher_suite,&ssl->cs);
ja3s_c_str = calloc(6, 1);
snprintf(ja3s_c_str, 6, "%u", ssl->cipher_suite);
ssl_process_server_session_id(ssl,ssl->decoder,session_id.data, ssl_process_server_session_id(ssl,ssl->decoder,session_id.data,
session_id.len); session_id.len);
@ -324,6 +432,13 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
explain(ssl , "extensions\n"); explain(ssl , "extensions\n");
while(data->len) { while(data->len) {
SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex);
if(!ja3s_ex_str)
ja3s_ex_str = calloc(7, 1);
else
ja3s_ex_str = realloc(ja3s_ex_str, strlen(ja3s_ex_str) + 7);
snprintf(ja3s_ex_str + strlen(ja3s_ex_str), 7, "%u-", ex);
if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) {
decode_extension(ssl,dir,seg,data); decode_extension(ssl,dir,seg,data);
P_(P_RH){ P_(P_RH){
@ -333,8 +448,58 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
} }
LF; LF;
} }
if(ja3s_ex_str && ja3s_ex_str[strlen(ja3s_ex_str) - 1] == '-')
ja3s_ex_str[strlen(ja3s_ex_str) - 1] = '\0';
} }
if(!ja3s_ver_str) {
ja3s_ver_str = calloc(1, 1);
*ja3s_ver_str = '\0';
}
if(!ja3s_c_str) {
ja3s_c_str = calloc(1, 1);
*ja3s_c_str = '\0';
}
if(!ja3s_ex_str) {
ja3s_ex_str = calloc(1, 1);
*ja3s_ex_str = '\0';
}
int ja3s_str_len =
strlen(ja3s_ver_str) + 1
+ strlen(ja3s_c_str) + 1
+ strlen(ja3s_ex_str) + 1;
ja3s_str = calloc(ja3s_str_len, 1);
snprintf(ja3s_str, ja3s_str_len, "%s,%s,%s",
ja3s_ver_str, ja3s_c_str, ja3s_ex_str);
MD5_CTX md5;
UCHAR tmp[16];
MD5_Init(&md5);
MD5_Update(&md5, ja3s_str, ja3s_str_len);
MD5_Final(tmp,&md5);
ja3s_fp = calloc(33,1);
*ja3s_fp = '\0';
for(int i=0; i<16; i++) {
snprintf(ja3s_fp + strlen(ja3s_fp), 3, "%02x", tmp[i]);
}
json_object_object_add(jobj, "ja3s_str", json_object_new_string(ja3s_str));
json_object_object_add(jobj, "ja3s_fp", json_object_new_string(ja3s_fp));
explain(ssl, "ja3s string: %s\n", ja3s_str);
explain(ssl, "ja3s fingerprint: %s\n", ja3s_fp);
free(ja3s_fp);
free(ja3s_str);
free(ja3s_ver_str);
free(ja3s_c_str);
free(ja3s_ex_str);
return(0); return(0);
} }
@ -2664,6 +2829,78 @@ static int decode_extension(ssl,dir,seg,data)
return(0); return(0);
} }
// Extension #10 supported_groups (renamed from "elliptic_curves")
static int decode_extension_supported_groups(ssl,dir,seg,data)
ssl_obj *ssl;
int dir;
segment *seg;
Data *data;
{
int r,p;
UINT4 l,g;
char *ja3_ec_str = NULL;
SSL_DECODE_UINT16(ssl,"extension length",0,data,&l);
if(dir==DIR_I2R){
SSL_DECODE_UINT16(ssl,"supported_groups list length",0,data,&l);
LF;
while(l) {
p=data->len;
SSL_DECODE_UINT16(ssl, "supported group", 0, data, &g);
if(!ja3_ec_str)
ja3_ec_str = calloc(7, 1);
else
ja3_ec_str = realloc(ja3_ec_str, strlen(ja3_ec_str) + 7);
snprintf(ja3_ec_str + strlen(ja3_ec_str), 7, "%u-", g);
l-=(p-data->len);
}
if(ja3_ec_str && ja3_ec_str[strlen(ja3_ec_str) - 1] == '-')
ja3_ec_str[strlen(ja3_ec_str) - 1] = '\0';
}
else{
data->len-=l;
data->data+=l;
}
ssl->cur_ja3_ec_str = ja3_ec_str;
return(0);
}
// Extension #11 ec_point_formats
static int decode_extension_ec_point_formats(ssl,dir,seg,data)
ssl_obj *ssl;
int dir;
segment *seg;
Data *data;
{
int r,p;
UINT4 l,f;
char *ja3_ecp_str = NULL;
SSL_DECODE_UINT16(ssl,"extension length",0,data,&l);
if(dir==DIR_I2R){
SSL_DECODE_UINT8(ssl,"ec_point_formats list length",0,data,&l);
LF;
while(l) {
p=data->len;
SSL_DECODE_UINT8(ssl, "ec point format", 0, data, &f);
if(!ja3_ecp_str)
ja3_ecp_str = calloc(5, 1);
else
ja3_ecp_str = realloc(ja3_ecp_str, strlen(ja3_ecp_str) + 5);
snprintf(ja3_ecp_str + strlen(ja3_ecp_str), 5, "%u-", f);
l-=(p-data->len);
}
if(ja3_ecp_str && ja3_ecp_str[strlen(ja3_ecp_str) - 1] == '-')
ja3_ecp_str[strlen(ja3_ecp_str) - 1] = '\0';
}
else{
data->len-=l;
data->data+=l;
}
ssl->cur_ja3_ecp_str = ja3_ecp_str;
return(0);
}
decoder extension_decoder[] = { decoder extension_decoder[] = {
{ {
@ -2719,12 +2956,12 @@ decoder extension_decoder[] = {
{ {
10, 10,
"supported_groups", "supported_groups",
decode_extension decode_extension_supported_groups
}, },
{ {
11, 11,
"ec_point_formats", "ec_point_formats",
decode_extension decode_extension_ec_point_formats
}, },
{ {
12, 12,

View file

@ -109,6 +109,8 @@ typedef struct ssl_obj_ {
int indent_depth; int indent_depth;
int indent_name_len; int indent_name_len;
struct json_object *cur_json_st; struct json_object *cur_json_st;
char *cur_ja3_ec_str;
char *cur_ja3_ecp_str;
} ssl_obj; } ssl_obj;
typedef struct decoder_ { typedef struct decoder_ {