mirror of
https://github.com/zeek/zeek.git
synced 2025-10-15 21:18:20 +00:00
213 lines
6.7 KiB
JavaScript
213 lines
6.7 KiB
JavaScript
# Analyzer for SSL messages (general part).
|
|
# To be used in conjunction with an SSL record-layer analyzer.
|
|
# Separation is necessary due to possible fragmentation of SSL records.
|
|
|
|
type SSLRecord(is_orig: bool) = record {
|
|
head0 : uint8;
|
|
head1 : uint8;
|
|
head2 : uint8;
|
|
head3 : uint8;
|
|
head4 : uint8;
|
|
rec : RecordText(this)[] &length=length, &requires(content_type);
|
|
} &length = length+5, &byteorder=bigendian,
|
|
&let {
|
|
version : int =
|
|
$context.connection.determine_ssl_record_layer(head0, head1, head2, head3, head4, is_orig);
|
|
|
|
content_type : int = case version of {
|
|
SSLv20 -> head2+300;
|
|
default -> head0;
|
|
};
|
|
|
|
length : int = case version of {
|
|
# fail analyzer if the packet cannot be recognized as TLS.
|
|
UNKNOWN_VERSION -> 0;
|
|
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
|
|
default -> (head3 << 8) | head4;
|
|
};
|
|
};
|
|
|
|
type RecordText(rec: SSLRecord) = case $context.connection.state(rec.is_orig) of {
|
|
STATE_ENCRYPTED
|
|
-> ciphertext : CiphertextRecord(rec);
|
|
default
|
|
-> plaintext : PlaintextRecord(rec);
|
|
};
|
|
|
|
refine casetype PlaintextRecord += {
|
|
HANDSHAKE -> handshake : Handshake(rec);
|
|
V2_ERROR -> v2_error : V2Error(rec);
|
|
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec);
|
|
V2_CLIENT_MASTER_KEY -> v2_client_master_key : V2ClientMasterKey(rec);
|
|
V2_SERVER_HELLO -> v2_server_hello : V2ServerHello(rec);
|
|
};
|
|
|
|
type Handshake(rec: SSLRecord) = record {
|
|
# msg_type: uint8;
|
|
# length: uint24;
|
|
# data: bytestring &length=to_int()(length);
|
|
data: bytestring &restofdata;
|
|
};
|
|
|
|
######################################################################
|
|
# V2 Error Records (SSLv2 2.7.)
|
|
######################################################################
|
|
|
|
type V2Error(rec: SSLRecord) = record {
|
|
data : bytestring &restofdata &transient;
|
|
} &let {
|
|
error_code : uint16 = ((rec.head3 << 8) | rec.head4);
|
|
};
|
|
|
|
|
|
|
|
######################################################################
|
|
# V2 Client Hello (SSLv2 2.5.)
|
|
######################################################################
|
|
|
|
type V2ClientHello(rec: SSLRecord) = record {
|
|
csuit_len : uint16;
|
|
session_len : uint16;
|
|
chal_len : uint16;
|
|
ciphers : uint24[csuit_len/3];
|
|
session_id : uint8[session_len];
|
|
challenge : bytestring &length = chal_len;
|
|
} &length = 6 + csuit_len + session_len + chal_len, &let {
|
|
client_version : int = rec.version;
|
|
};
|
|
|
|
|
|
|
|
######################################################################
|
|
# V2 Server Hello (SSLv2 2.6.)
|
|
######################################################################
|
|
|
|
type V2ServerHello(rec: SSLRecord) = record {
|
|
#session_id_hit : uint8;
|
|
#cert_type : uint8;
|
|
server_version : uint16;
|
|
cert_len : uint16;
|
|
ciph_len : uint16;
|
|
conn_id_len : uint16;
|
|
cert_data : bytestring &length = cert_len;
|
|
ciphers : uint24[ciph_len/3];
|
|
conn_id_data : bytestring &length = conn_id_len;
|
|
} &let {
|
|
session_id_hit : uint8 = rec.head3;
|
|
cert_type : uint8 = rec.head4;
|
|
};
|
|
|
|
|
|
######################################################################
|
|
# V2 Client Master Key (SSLv2 2.5.)
|
|
######################################################################
|
|
|
|
type V2ClientMasterKey(rec: SSLRecord) = record {
|
|
cipher_kind_8 : uint8;
|
|
cl_key_len : uint16;
|
|
en_key_len : uint16;
|
|
key_arg_len : uint16;
|
|
cl_key_data : bytestring &length = cl_key_len &transient;
|
|
en_key_data : bytestring &length = en_key_len &transient;
|
|
key_arg_data : bytestring &length = key_arg_len &transient;
|
|
} &length = 7 + cl_key_len + en_key_len + key_arg_len, &let {
|
|
cipher_kind : int = (((rec.head3 << 16) | (rec.head4 << 8)) | cipher_kind_8);
|
|
# encryption starts for both sides after this message.
|
|
state_changed_client : bool = $context.connection.startEncryption(true);
|
|
state_changed_server : bool = $context.connection.startEncryption(false);
|
|
};
|
|
|
|
|
|
######################################################################
|
|
# initial datatype for binpac
|
|
######################################################################
|
|
|
|
type SSLPDU(is_orig: bool) = record {
|
|
records : SSLRecord(is_orig)[] &transient;
|
|
} &byteorder = bigendian;
|
|
|
|
|
|
######################################################################
|
|
# binpac analyzer for SSL including
|
|
######################################################################
|
|
|
|
refine connection SSL_Conn += {
|
|
|
|
function determine_ssl_record_layer(head0 : uint8, head1 : uint8,
|
|
head2 : uint8, head3: uint8, head4: uint8, is_orig: bool) : int
|
|
%{
|
|
// stop processing if we already had a protocol violation or otherwhise
|
|
// decided that we do not want to parse anymore. Just setting skip is not
|
|
// enough for the data that is already in the pipe.
|
|
if ( bro_analyzer()->Skipping() )
|
|
return UNKNOWN_VERSION;
|
|
|
|
// re-check record layer version to be sure that we still are synchronized with
|
|
// the data stream
|
|
if ( record_layer_version_ != UNKNOWN_VERSION && record_layer_version_ != SSLv20 )
|
|
{
|
|
uint16 version = (head1<<8) | head2;
|
|
if ( version != SSLv30 && version != TLSv10 &&
|
|
version != TLSv11 && version != TLSv12 )
|
|
{
|
|
bro_analyzer()->ProtocolViolation(fmt("Invalid version late in TLS connection. Packet reported version: %d", version));
|
|
bro_analyzer()->SetSkip(true);
|
|
return UNKNOWN_VERSION;
|
|
}
|
|
}
|
|
|
|
if ( record_layer_version_ != UNKNOWN_VERSION )
|
|
return record_layer_version_;
|
|
|
|
if ( head0 & 0x80 )
|
|
{
|
|
if ( head2 == 0x01 && is_orig ) // SSLv2 client hello.
|
|
{
|
|
uint16 version = (head3 << 8) | head4;
|
|
if ( version != SSLv20 && version != SSLv30 && version != TLSv10 &&
|
|
version != TLSv11 && version != TLSv12 )
|
|
{
|
|
bro_analyzer()->ProtocolViolation(fmt("Invalid version in SSL client hello. Version: %d", version));
|
|
bro_analyzer()->SetSkip(true);
|
|
return UNKNOWN_VERSION;
|
|
}
|
|
|
|
else
|
|
return SSLv20;
|
|
}
|
|
|
|
else if ( head2 == 0x04 && head4 < 2 && ! is_orig ) // SSLv2 server hello. This connection will continue using SSLv2.
|
|
{
|
|
record_layer_version_ = SSLv20;
|
|
return SSLv20;
|
|
}
|
|
|
|
else // this is not SSL or TLS.
|
|
{
|
|
bro_analyzer()->ProtocolViolation(fmt("Invalid headers in SSL connection. Head1: %d, head2: %d, head3: %d", head1, head2, head3));
|
|
bro_analyzer()->SetSkip(true);
|
|
return UNKNOWN_VERSION;
|
|
}
|
|
}
|
|
|
|
uint16 version = (head1<<8) | head2;
|
|
if ( version != SSLv30 && version != TLSv10 &&
|
|
version != TLSv11 && version != TLSv12 )
|
|
{
|
|
bro_analyzer()->ProtocolViolation(fmt("Invalid version in TLS connection. Version: %d", version));
|
|
bro_analyzer()->SetSkip(true);
|
|
return UNKNOWN_VERSION;
|
|
}
|
|
|
|
if ( head0 >=20 && head0 <= 30 )
|
|
{ // ok, set record layer version, this never can be downgraded to v2
|
|
record_layer_version_ = version;
|
|
return version;
|
|
}
|
|
|
|
bro_analyzer()->ProtocolViolation(fmt("Invalid type in TLS connection. Version: %d, Type: %d", version, head0));
|
|
bro_analyzer()->SetSkip(true);
|
|
return UNKNOWN_VERSION;
|
|
%}
|
|
|
|
};
|