mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 12:38:20 +00:00
Make SSL/TLS version detection less brittle.
This still cannot deal with v2 hellos that use the long length. On the other hand - OpenSSL also cannot deal with these and we should not see many sslv2 connections in any case - so... they probably would not work in practice in any case.
This commit is contained in:
parent
8ce3cf65f2
commit
594975c93d
2 changed files with 68 additions and 29 deletions
|
@ -293,6 +293,14 @@ refine connection SSL_Conn += {
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
function proc_check_v2_server_hello_version(version: uint16) : bool
|
||||||
|
%{
|
||||||
|
if ( version != SSLv20 )
|
||||||
|
bro_analyzer()->ProtocolViolation(fmt("Invalid version in SSL server hello. Version: %d", version));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#refine typeattr ChangeCipherSpec += &let {
|
#refine typeattr ChangeCipherSpec += &let {
|
||||||
|
@ -337,6 +345,8 @@ refine typeattr V2ServerHello += &let {
|
||||||
proc : bool = $context.connection.proc_server_hello(rec, server_version, 0,
|
proc : bool = $context.connection.proc_server_hello(rec, server_version, 0,
|
||||||
conn_id_data, 0, 0, ciphers, 0);
|
conn_id_data, 0, 0, ciphers, 0);
|
||||||
|
|
||||||
|
check_v2 : bool = $context.connection.proc_check_v2_server_hello_version(server_version);
|
||||||
|
|
||||||
cert : bool = $context.connection.proc_v2_certificate(rec, cert_data)
|
cert : bool = $context.connection.proc_v2_certificate(rec, cert_data)
|
||||||
&requires(proc);
|
&requires(proc);
|
||||||
};
|
};
|
||||||
|
@ -346,8 +356,7 @@ refine typeattr Certificate += &let {
|
||||||
};
|
};
|
||||||
|
|
||||||
refine typeattr V2ClientMasterKey += &let {
|
refine typeattr V2ClientMasterKey += &let {
|
||||||
proc : bool = $context.connection.proc_v2_client_master_key(rec, cipher_kind)
|
proc : bool = $context.connection.proc_v2_client_master_key(rec, cipher_kind);
|
||||||
&requires(state_changed);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
refine typeattr UnknownHandshake += &let {
|
refine typeattr UnknownHandshake += &let {
|
||||||
|
|
|
@ -36,16 +36,14 @@ type SSLRecord(is_orig: bool) = record {
|
||||||
} &length = length+5, &byteorder=bigendian,
|
} &length = length+5, &byteorder=bigendian,
|
||||||
&let {
|
&let {
|
||||||
version : int =
|
version : int =
|
||||||
$context.connection.determine_ssl_version(head0, head1, head2);
|
$context.connection.determine_ssl_record_layer(head0, head1, head2, head3, head4);
|
||||||
|
|
||||||
content_type : int = case version of {
|
content_type : int = case version of {
|
||||||
# UNKNOWN_VERSION -> 0; assume tls on unknown version
|
|
||||||
SSLv20 -> head2+300;
|
SSLv20 -> head2+300;
|
||||||
default -> head0;
|
default -> head0;
|
||||||
};
|
};
|
||||||
|
|
||||||
length : int = case version of {
|
length : int = case version of {
|
||||||
# UNKNOWN_VERSION -> 0; assume tls on unknown version
|
|
||||||
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
|
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
|
||||||
default -> (head3 << 8) | head4;
|
default -> (head3 << 8) | head4;
|
||||||
};
|
};
|
||||||
|
@ -277,11 +275,6 @@ type CertificateList = X509Certificate[] &until($input.length() == 0);
|
||||||
type Certificate(rec: SSLRecord) = record {
|
type Certificate(rec: SSLRecord) = record {
|
||||||
length : uint24;
|
length : uint24;
|
||||||
certificates : CertificateList &length = to_int()(length);
|
certificates : CertificateList &length = to_int()(length);
|
||||||
} &let {
|
|
||||||
state_changed_client : bool =
|
|
||||||
$context.connection.startEncryption(true);
|
|
||||||
state_changed_server : bool =
|
|
||||||
$context.connection.startEncryption(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,6 +338,9 @@ type V2ClientMasterKey(rec: SSLRecord) = record {
|
||||||
key_arg_data : bytestring &length = key_arg_len &transient;
|
key_arg_data : bytestring &length = key_arg_len &transient;
|
||||||
} &length = 7 + cl_key_len + en_key_len + key_arg_len, &let {
|
} &length = 7 + cl_key_len + en_key_len + key_arg_len, &let {
|
||||||
cipher_kind : int = (((rec.head3 << 16) | (rec.head4 << 8)) | cipher_kind_8);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -435,41 +431,75 @@ refine connection SSL_Conn += {
|
||||||
%member{
|
%member{
|
||||||
int client_state_;
|
int client_state_;
|
||||||
int server_state_;
|
int server_state_;
|
||||||
int old_state_;
|
int record_layer_version_;
|
||||||
bool hello_requested_;
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%init{
|
%init{
|
||||||
server_state_ = STATE_CLEAR;
|
server_state_ = STATE_CLEAR;
|
||||||
client_state_ = STATE_CLEAR;
|
client_state_ = STATE_CLEAR;
|
||||||
|
record_layer_version_ = UNKNOWN_VERSION;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function determine_ssl_version(head0 : uint8, head1 : uint8,
|
function determine_ssl_record_layer(head0 : uint8, head1 : uint8,
|
||||||
head2 : uint8) : int
|
head2 : uint8, head3: uint8, head4: uint8) : int
|
||||||
%{
|
%{
|
||||||
if ( head0 >= 20 && head0 <= 23 &&
|
if ( record_layer_version_ != UNKNOWN_VERSION )
|
||||||
head1 == 0x03 && head2 <= 0x03 )
|
return record_layer_version_;
|
||||||
// This is most probably SSL version 3.
|
|
||||||
return (head1 << 8) | head2;
|
|
||||||
|
|
||||||
else if ( head0 >= 128 && head2 < 5 && head2 != 3 )
|
if ( head0 & 0x80 )
|
||||||
// Not very strong evidence, but we suspect
|
{
|
||||||
// this to be SSLv2.
|
if ( head2 == 0x01 ) // SSLv2 client hello.
|
||||||
return SSLv20;
|
{
|
||||||
|
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));
|
||||||
|
return UNKNOWN_VERSION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SSLv20;
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else if ( head2 == 0x04 ) // 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));
|
||||||
|
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));
|
||||||
return UNKNOWN_VERSION;
|
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));
|
||||||
|
return UNKNOWN_VERSION;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function client_state() : int %{ return client_state_; %}
|
function client_state() : int %{ return client_state_; %}
|
||||||
function server_state() : int %{ return client_state_; %}
|
function server_state() : int %{ return client_state_; %}
|
||||||
function state(is_orig: bool) : int
|
function state(is_orig: bool) : int
|
||||||
%{
|
%{
|
||||||
if ( is_orig )
|
if ( is_orig )
|
||||||
return client_state_;
|
return client_state_;
|
||||||
else
|
else
|
||||||
return server_state_;
|
return server_state_;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function startEncryption(is_orig: bool) : bool
|
function startEncryption(is_orig: bool) : bool
|
||||||
%{
|
%{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue