ja3/zeek/ja3.zeek
Patrick Kelley c3f8aeaa1f Initial
2025-05-07 14:11:26 -04:00

156 lines
4.3 KiB
Plaintext

# This Zeek script appends JA3 to ssl.log
# Version 1.4 (January 2020)
#
# Authors: John B. Althouse (jalthouse@salesforce.com) & Jeff Atkinson (jatkinson@salesforce.com)
#
# Copyright (c) 2017, salesforce.com, inc.
# All rights reserved.
# Licensed under the BSD 3-Clause license.
# For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
module JA3;
export {
redef enum Log::ID += { LOG };
}
type TLSFPStorage: record {
client_version: count &default=0 &log;
client_ciphers: string &default="" &log;
extensions: string &default="" &log;
e_curves: string &default="" &log;
ec_point_fmt: string &default="" &log;
};
redef record connection += {
tlsfp: TLSFPStorage &optional;
};
redef record SSL::Info += {
ja3: string &optional &log;
# LOG FIELD VALUES ##
# ja3_version: string &optional &log;
# ja3_ciphers: string &optional &log;
# ja3_extensions: string &optional &log;
# ja3_ec: string &optional &log;
# ja3_ec_fmt: string &optional &log;
};
# Google. https://tools.ietf.org/html/draft-davidben-tls-grease-01
const grease: set[int] = {
2570,
6682,
10794,
14906,
19018,
23130,
27242,
31354,
35466,
39578,
43690,
47802,
51914,
56026,
60138,
64250
};
const sep = "-";
event zeek_init() {
Log::create_stream(JA3::LOG,[$columns=TLSFPStorage, $path="tlsfp"]);
}
event ssl_extension(c: connection, is_orig: bool, code: count, val: string)
{
if ( is_orig == T ) {
if ( code in grease ) {
return;
}
if ( ! c?$tlsfp ){
c$tlsfp=TLSFPStorage();
}
if ( c$tlsfp$extensions == "" ) {
c$tlsfp$extensions = cat(code);
}
else {
c$tlsfp$extensions = string_cat(c$tlsfp$extensions, sep,cat(code));
}
}
}
event ssl_extension_ec_point_formats(c: connection, is_orig: bool, point_formats: index_vec)
{
if ( is_orig == T ) {
if ( !c?$tlsfp )
c$tlsfp=TLSFPStorage();
for ( i in point_formats ) {
if ( point_formats[i] in grease ) {
next;
}
if ( c$tlsfp$ec_point_fmt == "" ) {
c$tlsfp$ec_point_fmt += cat(point_formats[i]);
}
else {
c$tlsfp$ec_point_fmt += string_cat(sep,cat(point_formats[i]));
}
}
}
}
event ssl_extension_elliptic_curves(c: connection, is_orig: bool, curves: index_vec)
{
if ( !c?$tlsfp )
c$tlsfp=TLSFPStorage();
if ( is_orig == T ) {
for ( i in curves ) {
if ( curves[i] in grease ) {
next;
}
if ( c$tlsfp$e_curves == "" ) {
c$tlsfp$e_curves += cat(curves[i]);
}
else {
c$tlsfp$e_curves += string_cat(sep,cat(curves[i]));
}
}
}
}
@if ( ( Version::number >= 20600 ) || ( Version::number == 20500 && Version::info$commit >= 944 ) )
event ssl_client_hello(c: connection, version: count, record_version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec, comp_methods: index_vec) &priority=1
@else
event ssl_client_hello(c: connection, version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec) &priority=1
@endif
{
if ( !c?$tlsfp )
c$tlsfp=TLSFPStorage();
c$tlsfp$client_version = version;
for ( i in ciphers ) {
if ( ciphers[i] in grease ) {
next;
}
if ( c$tlsfp$client_ciphers == "" ) {
c$tlsfp$client_ciphers += cat(ciphers[i]);
}
else {
c$tlsfp$client_ciphers += string_cat(sep,cat(ciphers[i]));
}
}
local sep2 = ",";
local ja3_string = string_cat(cat(c$tlsfp$client_version),sep2,c$tlsfp$client_ciphers,sep2,c$tlsfp$extensions,sep2,c$tlsfp$e_curves,sep2,c$tlsfp$ec_point_fmt);
local tlsfp_1 = md5_hash(ja3_string);
c$ssl$ja3 = tlsfp_1;
# LOG FIELD VALUES ##
#c$ssl$ja3_version = cat(c$tlsfp$client_version);
#c$ssl$ja3_ciphers = c$tlsfp$client_ciphers;
#c$ssl$ja3_extensions = c$tlsfp$extensions;
#c$ssl$ja3_ec = c$tlsfp$e_curves;
#c$ssl$ja3_ec_fmt = c$tlsfp$ec_point_fmt;
#
# FOR DEBUGGING ##
#print "JA3: "+tlsfp_1+" Fingerprint String: "+ja3_string;
}