mirror of
https://github.com/zeek/zeek.git
synced 2025-10-16 05:28:20 +00:00
Initial drop of updated ssl.bro
This commit is contained in:
parent
68d4e612f1
commit
2c975495d3
1 changed files with 137 additions and 130 deletions
|
@ -5,54 +5,84 @@
|
|||
@load weird
|
||||
@load ssl-ciphers
|
||||
@load ssl-errors
|
||||
@load functions
|
||||
|
||||
module SSL;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { SSL_SERVER };
|
||||
type ServerLog: record {
|
||||
ts: time; # timestamp
|
||||
client_address: addr; # client address
|
||||
client_port: port; # client port
|
||||
cert_subject: X509; # certificate subject
|
||||
not_valid_before: time; # certificate valid time constraint
|
||||
not_valid_after: time; # certificate valid time constraint
|
||||
ssl_tls_version: string; # version number
|
||||
weak_client_ciphers_offered: bool; # true if client offered insecure ciphers
|
||||
weak_server_ciphers_offered: bool; # true if server offered insecure ciphers
|
||||
weak_cipher_agreed: bool; # true if insecure cipher agreed upon for use
|
||||
};
|
||||
|
||||
|
||||
# If true, Bro stores the client and server cipher specs and performs
|
||||
# additional tests. This costs an extra amount of memory (normally
|
||||
# only for a short time) but enables detecting of non-intersecting
|
||||
# cipher sets, for example.
|
||||
const ssl_compare_cipherspecs = T &redef;
|
||||
|
||||
# Whether to analyze certificates seen in SSL connections.
|
||||
const ssl_analyze_certificates = T &redef;
|
||||
|
||||
# If we analyze SSL certificates, we can choose to store them.
|
||||
const ssl_store_certificates = T &redef;
|
||||
|
||||
# Path where we dump the certificates into. If it's empty,
|
||||
# use the current directory.
|
||||
const ssl_store_cert_path = "certs" &redef;
|
||||
|
||||
# If we analyze SSL certificates, we can choose to verify them.
|
||||
const ssl_verify_certificates = T &redef;
|
||||
|
||||
# This is the path where OpenSSL looks after the trusted certificates.
|
||||
# If empty, the default path will be used.
|
||||
const x509_trusted_cert_path = "" &redef;
|
||||
|
||||
# Whether to store key-material exchanged in the handshaking phase.
|
||||
const ssl_store_key_material = F &redef;
|
||||
|
||||
# Report weak/unknown ciphers in CLIENT_HELLO, SSLv2 SERVER_HELLO.
|
||||
const ssl_report_client_weak = F &redef;
|
||||
const ssl_report_client_unknown = F &redef;
|
||||
const ssl_report_server_weak = F &redef;
|
||||
|
||||
# Log all ciphers.
|
||||
# TODO: dga 3/11 Discarded for now; could be re-added, perhaps as a separate stream for the curious
|
||||
# const ssl_log_ciphers = T &redef;
|
||||
|
||||
global ssl_ports = {
|
||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp,
|
||||
} &redef;
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
Log::create_stream( "SSL_SERVER", "SSL::ServerLog" );
|
||||
Log::add_default_filter( "SSL_SERVER" );
|
||||
}
|
||||
|
||||
global ssl_log = open_log_file("ssl") &redef;
|
||||
|
||||
redef enum Notice += {
|
||||
SSL_X509Violation, # blanket X509 error
|
||||
SSL_SessConIncon, # session data not consistent with connection
|
||||
};
|
||||
|
||||
|
||||
const SSLv2 = 0x0002;
|
||||
const SSLv3 = 0x0300;
|
||||
const TLSv10 = 0x0301;
|
||||
const TLSv11 = 0x0302;
|
||||
|
||||
# If true, Bro stores the client and server cipher specs and performs
|
||||
# additional tests. This costs an extra amount of memory (normally
|
||||
# only for a short time) but enables detecting of non-intersecting
|
||||
# cipher sets, for example.
|
||||
const ssl_compare_cipherspecs = T &redef;
|
||||
|
||||
# Whether to analyze certificates seen in SSL connections.
|
||||
const ssl_analyze_certificates = T &redef;
|
||||
|
||||
# If we analyze SSL certificates, we can choose to store them.
|
||||
const ssl_store_certificates = T &redef;
|
||||
|
||||
# Path where we dump the certificates into. If it's empty,
|
||||
# use the current directory.
|
||||
const ssl_store_cert_path = "certs" &redef;
|
||||
|
||||
# If we analyze SSL certificates, we can choose to verify them.
|
||||
const ssl_verify_certificates = T &redef;
|
||||
|
||||
# This is the path where OpenSSL looks after the trusted certificates.
|
||||
# If empty, the default path will be used.
|
||||
const x509_trusted_cert_path = "" &redef;
|
||||
|
||||
# Whether to store key-material exchanged in the handshaking phase.
|
||||
const ssl_store_key_material = F &redef;
|
||||
|
||||
# Report weak/unknown ciphers in CLIENT_HELLO, SSLv2 SERVER_HELLO.
|
||||
const ssl_report_client_weak = F &redef;
|
||||
const ssl_report_client_unknown = F &redef;
|
||||
const ssl_report_server_weak = F &redef;
|
||||
|
||||
# Log all ciphers.
|
||||
const ssl_log_ciphers = T &redef;
|
||||
|
||||
# NOTE: this is a 'local' port format for your site
|
||||
# --- well-known ports for ssl ---------
|
||||
redef capture_filters += {
|
||||
|
@ -69,11 +99,6 @@ redef capture_filters += {
|
|||
["pop3s"] = "tcp port 995"
|
||||
};
|
||||
|
||||
global ssl_ports = {
|
||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp,
|
||||
} &redef;
|
||||
|
||||
redef dpd_config += {
|
||||
[[ANALYZER_SSL, ANALYZER_SSL_BINPAC]] = [$ports = ssl_ports]
|
||||
};
|
||||
|
@ -130,20 +155,24 @@ redef Weird::weird_action += {
|
|||
"SSLv3_data_without_full_handshake"]] = Weird::WEIRD_IGNORE
|
||||
};
|
||||
|
||||
|
||||
global SSL_cipherCount: table[count] of count &default = 0;
|
||||
|
||||
# track weak ciphers offered by client and/or server until it can be logged
|
||||
global ssl_weak_client_ciphers: table[conn_id] of bool &read_expire = 2 hrs;
|
||||
global ssl_weak_server_ciphers: table[conn_id] of bool &read_expire = 2 hrs;
|
||||
|
||||
|
||||
type ssl_connection_info: record {
|
||||
id: count; # the log identifier number
|
||||
connection_id: conn_id; # IP connection information
|
||||
version: string; # version assosciated with connection
|
||||
version: string; # version associated with connection
|
||||
client_cert: X509;
|
||||
server_cert: X509;
|
||||
id_index: string; # index for associated SSL_sessionID
|
||||
handshake_cipher: string; # agreed-upon cipher for session/conn.
|
||||
};
|
||||
|
||||
# SSL_sessionID index - used to track version assosciated with a session id.
|
||||
# SSL_sessionID index - used to track version associated with a session id.
|
||||
type SSL_sessionID_record: record {
|
||||
num_reuse: count;
|
||||
id: SSL_sessionID; # literal session ID
|
||||
|
@ -181,10 +210,7 @@ function new_ssl_connection(c: connection)
|
|||
info$connection_id = conn;
|
||||
|
||||
ssl_connections[conn] = info;
|
||||
append_addl(c, fmt("#%d", new_id));
|
||||
|
||||
print ssl_log, fmt("%.6f #%d %s start",
|
||||
network_time(), new_id, id_string(conn));
|
||||
append_addl( c, fmt( "#%d", new_id ) );
|
||||
}
|
||||
|
||||
function new_sessionID_record(session: SSL_sessionID)
|
||||
|
@ -231,28 +257,19 @@ function ssl_con2str(c: connection): string
|
|||
function lookup_ssl_conn(c: connection, func: string, log_if_new: bool)
|
||||
{
|
||||
if ( c$id !in ssl_connections )
|
||||
{
|
||||
new_ssl_connection(c);
|
||||
|
||||
if ( log_if_new )
|
||||
print ssl_log,
|
||||
fmt("%.6f #%d creating new SSL connection in %s",
|
||||
network_time(), ssl_connections[c$id]$id, func);
|
||||
}
|
||||
}
|
||||
|
||||
event ssl_conn_weak(name: string, c: connection)
|
||||
{
|
||||
lookup_ssl_conn(c, "ssl_conn_weak", T);
|
||||
print ssl_log, fmt("%.6f #%d %s",
|
||||
network_time(), ssl_connections[c$id]$id, name);
|
||||
}
|
||||
|
||||
# --- SSL events -------------------
|
||||
|
||||
event ssl_certificate_seen(c: connection, is_server: bool)
|
||||
{
|
||||
# Called whenever there's an certificate to analyze.
|
||||
# Called whenever there's a certificate to analyze.
|
||||
# we could do something here, like...
|
||||
|
||||
# if ( c$id$orig_h in hostsToIgnore )
|
||||
|
@ -288,12 +305,6 @@ event ssl_certificate(c: connection, cert: X509, is_server: bool)
|
|||
ssl_sessionIDs[conn$id_index]$server_cert$subject =
|
||||
cert$subject;
|
||||
}
|
||||
|
||||
print ssl_log, fmt("%.6f #%d X.509 %s issuer %s",
|
||||
network_time(), conn$id, direction, cert$issuer);
|
||||
|
||||
print ssl_log, fmt("%.6f #%d X.509 %s subject %s",
|
||||
network_time(), conn$id, direction, cert$subject);
|
||||
}
|
||||
|
||||
event ssl_conn_attempt(c: connection, version: count,
|
||||
|
@ -303,30 +314,28 @@ event ssl_conn_attempt(c: connection, version: count,
|
|||
local conn = ssl_connections[c$id];
|
||||
local version_string = ssl_get_version_string(version);
|
||||
|
||||
print ssl_log, fmt("%.6f #%d SSL connection attempt %s",
|
||||
network_time(), conn$id, version_string);
|
||||
|
||||
conn$version = version_string;
|
||||
|
||||
local has_weak_ciphers = F;
|
||||
for ( cs in ciphers )
|
||||
{ # display a list of the cipher suites
|
||||
# Demo: report clients who support weak ciphers.
|
||||
if ( ssl_report_client_weak && cs in myWeakCiphers )
|
||||
if ( cs in myWeakCiphers )
|
||||
{
|
||||
has_weak_ciphers = T;
|
||||
event ssl_conn_weak(
|
||||
fmt("SSL client supports weak cipher: %s (0x%x)",
|
||||
ssl_get_cipher_name(cs), cs), c);
|
||||
}
|
||||
|
||||
# Demo: report unknown ciphers.
|
||||
if ( ssl_report_client_unknown && cs !in ssl_cipher_desc )
|
||||
event ssl_conn_weak(
|
||||
fmt("SSL: unknown cipher-spec: %s (0x%x)",
|
||||
ssl_get_cipher_name(cs), cs), c);
|
||||
|
||||
if ( ssl_log_ciphers )
|
||||
print ssl_log, fmt("%.6f #%d client cipher %s (0x%x)",
|
||||
network_time(), conn$id,
|
||||
ssl_get_cipher_name(cs), cs);
|
||||
}
|
||||
|
||||
ssl_weak_client_ciphers[ c$id ] = has_weak_ciphers;
|
||||
}
|
||||
|
||||
event ssl_conn_server_reply(c: connection, version: count,
|
||||
|
@ -337,27 +346,28 @@ event ssl_conn_server_reply(c: connection, version: count,
|
|||
local conn = ssl_connections[c$id];
|
||||
local version_string = ssl_get_version_string(version);
|
||||
|
||||
print ssl_log, fmt("%.6f #%d SSL connection server reply, %s",
|
||||
network_time(), conn$id, version_string);
|
||||
# print ssl_log, fmt("%.6f #%d SSL connection server reply, %s",
|
||||
# network_time(), conn$id, version_string);
|
||||
|
||||
conn$version = version_string;
|
||||
|
||||
local has_weak_ciphers = F;
|
||||
for ( cs in ciphers )
|
||||
{
|
||||
# Demo: report servers who support weak ciphers.
|
||||
if ( ssl_report_server_weak && version == SSLv2 &&
|
||||
cs in myWeakCiphers )
|
||||
{
|
||||
has_weak_ciphers = T;
|
||||
event ssl_conn_weak(
|
||||
fmt("SSLv2 server supports weak cipher: %s (0x%x)",
|
||||
ssl_get_cipher_name(cs), cs), c);
|
||||
|
||||
if ( ssl_log_ciphers )
|
||||
print ssl_log, fmt("%.6f #%d server cipher %s (0x%x)",
|
||||
network_time(), conn$id,
|
||||
ssl_get_cipher_name(cs), cs);
|
||||
}
|
||||
}
|
||||
|
||||
ssl_weak_server_ciphers[ c$id ] = has_weak_ciphers;
|
||||
}
|
||||
|
||||
event ssl_conn_established(c: connection, version: count, cipher_suite: count)
|
||||
{
|
||||
lookup_ssl_conn(c, "ssl_conn_established", T);
|
||||
|
@ -365,25 +375,34 @@ event ssl_conn_established(c: connection, version: count, cipher_suite: count)
|
|||
local conn = ssl_connections[c$id];
|
||||
local version_string = ssl_get_version_string(version);
|
||||
|
||||
print ssl_log,
|
||||
fmt("%.6f #%d handshake finished, %s",
|
||||
network_time(), conn$id, version_string);
|
||||
|
||||
local has_weak_ciphers = F;
|
||||
if ( cipher_suite in myWeakCiphers )
|
||||
{
|
||||
has_weak_ciphers = T;
|
||||
event ssl_conn_weak(fmt("%.6f #%d weak cipher: %s (0x%x)",
|
||||
network_time(), conn$id,
|
||||
ssl_get_cipher_name(cipher_suite), cipher_suite), c);
|
||||
|
||||
if ( ssl_log_ciphers )
|
||||
print ssl_log, fmt("%.6f #%d connection cipher %s (0x%x)",
|
||||
network_time(), conn$id,
|
||||
ssl_get_cipher_name(cipher_suite), cipher_suite);
|
||||
}
|
||||
|
||||
++SSL_cipherCount[cipher_suite];
|
||||
|
||||
# This should be the version identified with the session, unless
|
||||
# there is some renegotiation. That will be caught later.
|
||||
conn$version = version_string;
|
||||
|
||||
# log the connection
|
||||
Log::write( "SSL_SERVER", [ $ts = network_time(),
|
||||
$client_address = c$id$orig_h,
|
||||
$client_port = c$id$orig_p,
|
||||
$cert_subject = conn$client_cert$subject,
|
||||
# TODO: dga 3/11 The following are not yet picked up
|
||||
# $not_valid_before = ???,
|
||||
# $not_valid_after = ???,
|
||||
# $ssl_tls_version = ???,
|
||||
$weak_client_ciphers_offered = ssl_weak_client_ciphers[ c$id ],
|
||||
$weak_server_ciphers_offered = ssl_weak_server_ciphers[ c$id ],
|
||||
$weak_cipher_agreed = has_weak_ciphers
|
||||
] );
|
||||
}
|
||||
|
||||
event process_X509_extensions(c: connection, ex: X509_extension)
|
||||
|
@ -394,8 +413,6 @@ event process_X509_extensions(c: connection, ex: X509_extension)
|
|||
local msg = fmt("%.6f #%d X.509 extensions: ", network_time(), conn$id);
|
||||
for ( i in ex )
|
||||
msg = fmt("%s, %s", msg, ex[i]);
|
||||
|
||||
print ssl_log, msg;
|
||||
}
|
||||
|
||||
event ssl_session_insertion(c: connection, id: SSL_sessionID)
|
||||
|
@ -406,10 +423,6 @@ event ssl_session_insertion(c: connection, id: SSL_sessionID)
|
|||
{
|
||||
new_ssl_connection(c);
|
||||
|
||||
print ssl_log,
|
||||
fmt("%.6f #%d creating new SSL connection in ssl_session_insertion",
|
||||
network_time(), ssl_connections[c$id]$id);
|
||||
|
||||
# None of the conn$object values will exist, so we leave this
|
||||
# to prevent needless crashing.
|
||||
return;
|
||||
|
@ -447,9 +460,6 @@ event ssl_conn_reused(c: connection, session_id: SSL_sessionID)
|
|||
local conn = ssl_connections[c$id];
|
||||
local id_index = md5_hash(session_id);
|
||||
|
||||
print ssl_log, fmt("%.6f #%d reusing former SSL session: %s",
|
||||
network_time(), conn$id, id_index);
|
||||
|
||||
# We cannot track sessions with SSLv2.
|
||||
if ( conn$version == ssl_get_version_string(SSLv2) )
|
||||
return;
|
||||
|
@ -496,10 +506,6 @@ event ssl_X509_error(c: connection, err: int, err_string: string)
|
|||
++c$hot;
|
||||
severity = "error";
|
||||
}
|
||||
|
||||
print ssl_log,
|
||||
fmt("%.6f #%d X.509 %s %s (%s)",
|
||||
network_time(), conn$id, severity, error, err_string);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
|
@ -517,20 +523,21 @@ event bro_init()
|
|||
|
||||
event bro_done()
|
||||
{
|
||||
print ssl_log, "Cipher suite statistics: ";
|
||||
for ( i in SSL_cipherCount )
|
||||
print ssl_log, fmt("%s (0x%x): %d", ssl_get_cipher_name(i), i,
|
||||
SSL_cipherCount[i]);
|
||||
|
||||
print ssl_log, ("count session ID");
|
||||
print ssl_log, ("----- ---------------------------------");
|
||||
for ( j in ssl_sessionIDs )
|
||||
if ( ssl_sessionIDs[j]$server_cert$subject != NONE )
|
||||
{
|
||||
print ssl_log,
|
||||
fmt("(%s) %s %s",
|
||||
ssl_sessionIDs[j]$num_reuse,
|
||||
ssl_sessionIDs[j]$server_cert$subject,
|
||||
j);
|
||||
}
|
||||
# TODO: Do we want this end-of-run logging back?
|
||||
# print ssl_log, "Cipher suite statistics: ";
|
||||
# for ( i in SSL_cipherCount )
|
||||
# print ssl_log, fmt("%s (0x%x): %d", ssl_get_cipher_name(i), i,
|
||||
# SSL_cipherCount[i]);
|
||||
#
|
||||
# print ssl_log, ("count session ID");
|
||||
# print ssl_log, ("----- ---------------------------------");
|
||||
# for ( j in ssl_sessionIDs )
|
||||
# if ( ssl_sessionIDs[j]$server_cert$subject != NONE )
|
||||
# {
|
||||
# print ssl_log,
|
||||
# fmt("(%s) %s %s",
|
||||
# ssl_sessionIDs[j]$num_reuse,
|
||||
# ssl_sessionIDs[j]$server_cert$subject,
|
||||
# j);
|
||||
# }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue