Spicy SSL - finish SSLv2 implementation

The events raised should be on-par with the Zeek TLS/SSL analyzer now.

DTLS support is still missing.
This commit is contained in:
Johanna Amann 2024-08-22 13:28:40 +01:00
parent 2aae73ea75
commit 91885f7518
3 changed files with 68 additions and 14 deletions

View file

@ -9,10 +9,11 @@ import zeek;
import spicy; import spicy;
on SSL::ClientHello -> event ssl_client_hello($conn, self.client_version, msg.record_version, cast<time>(self.random.gmt_unix_time), self.random.random_bytes, self.session_id, self.cipher_suites, self.compression_methods); on SSL::ClientHello -> event ssl_client_hello($conn, self.client_version, msg.record_version, cast<time>(self.random.gmt_unix_time), self.random.random_bytes, self.session_id, self.cipher_suites, self.compression_methods);
on SSL::SSL2ClientHello -> event ssl_client_hello($conn, self.client_version, 0, cast<time>(0), self.challenge, self.session_id, self.ciphers, self.compression_methods); on SSL::SSL2ClientHello -> event ssl_client_hello($conn, self.client_version, 0, cast<time>(0), self.challenge, self.session_id, self.ciphers, vector<uint16>());
on SSL::ServerHello -> event ssl_server_hello($conn, server_version, msg.record_version, cast<time>(self.gmt_unix_time), self.random_bytes, self.session_id, self.cipher_suite, self.compression_method); on SSL::ServerHello -> event ssl_server_hello($conn, server_version, msg.record_version, cast<time>(self.gmt_unix_time), self.random_bytes, self.session_id, self.cipher_suite, self.compression_method);
on SSL::ServerHelloOneThree -> event ssl_server_hello($conn, server_version, msg.record_version, cast<time>(self.gmt_unix_time), self.random_bytes, "", self.cipher_suite, 0); on SSL::ServerHelloOneThree -> event ssl_server_hello($conn, server_version, msg.record_version, cast<time>(self.gmt_unix_time), self.random_bytes, "", self.cipher_suite, 0);
on SSL::SSL2ServerHello::conn_id_data -> event ssl_server_hello($conn, self.server_version, 0, cast<time>(0), b"", self.conn_id_data, self.ciphers[0], 0);
on SSL::EllipticCurveList -> event ssl_extension_elliptic_curves($conn, SSL::get_direction(sh), self.elliptic_curve_list); on SSL::EllipticCurveList -> event ssl_extension_elliptic_curves($conn, SSL::get_direction(sh), self.elliptic_curve_list);
@ -24,12 +25,13 @@ on SSL::NewSessionTicket -> event ssl_session_ticket_handshake($conn, self.ticke
on SSL::PlaintextRecord::ccs -> event ssl_change_cipher_spec($conn, $is_orig); on SSL::PlaintextRecord::ccs -> event ssl_change_cipher_spec($conn, $is_orig);
# weird trigger for event ordering # weird trigger for event ordering
on SSL::PlaintextRecord::%done if ( msg.context().ccs_seen == 2 && content_type == 20 ) -> event ssl_established($conn);
on SSL::PlaintextRecord::trigger_zero if ( content_type == 23 && sh.tls_13 == True && ( sh.established == False || sh.both_sides_encrypted_first_time ) ) -> event ssl_probable_encrypted_handshake_message($conn, SSL::get_direction(sh), self.length); on SSL::PlaintextRecord::trigger_zero if ( content_type == 23 && sh.tls_13 == True && ( sh.established == False || sh.both_sides_encrypted_first_time ) ) -> event ssl_probable_encrypted_handshake_message($conn, SSL::get_direction(sh), self.length);
on SSL::PlaintextRecord::trigger_one if ( sh.both_sides_encrypted_first_time == True ) -> event ssl_established($conn); on SSL::PlaintextRecord::trigger_one if ( sh.both_sides_encrypted_first_time == True && content_type != 20 ) -> event ssl_established($conn);
on SSL::PlaintextRecord::trigger_two if ( self.encrypted == False ) -> event ssl_plaintext_data($conn, SSL::get_direction(sh), msg.record_version, content_type, self.length); on SSL::PlaintextRecord::trigger_two if ( self.encrypted == False ) -> event ssl_plaintext_data($conn, SSL::get_direction(sh), msg.record_version, content_type, self.length);
on SSL::PlaintextRecord::trigger_two if ( self.encrypted == True ) -> event ssl_encrypted_data($conn, SSL::get_direction(sh), msg.record_version, content_type, self.length); on SSL::PlaintextRecord::trigger_two if ( self.encrypted == True ) -> event ssl_encrypted_data($conn, SSL::get_direction(sh), msg.record_version, content_type, self.length);
on SSL::SSL2ClientMasterKey::%init -> event ssl_established($conn);
on SSL::Extension -> event ssl_extension($conn, SSL::get_direction(sh), self.code, self.raw); on SSL::Extension -> event ssl_extension($conn, SSL::get_direction(sh), self.code, self.raw);
on SSL::Handshake_message -> event ssl_handshake_message($conn, SSL::get_direction(sh), self.msg_type, self.length); on SSL::Handshake_message -> event ssl_handshake_message($conn, SSL::get_direction(sh), self.msg_type, self.length);

View file

@ -720,11 +720,34 @@ type SSL2Record = unit(lengthone: uint8, inout msg: Message, inout sh: Share) {
switch (SSL2ProtocolMessages(self.message_type)) { switch (SSL2ProtocolMessages(self.message_type)) {
SSL2ProtocolMessages::ssl_client_hello -> client_hello: SSL2ClientHello(self.length, msg, sh) &max-size=self.length; SSL2ProtocolMessages::ssl_client_hello -> client_hello: SSL2ClientHello(self.length, msg, sh) &max-size=self.length;
}; SSL2ProtocolMessages::ssl_server_hello -> server_hello: SSL2ServerHello(self.length, msg, sh) &max-size=self.length;
SSL2ProtocolMessages::ssl_client_master_key -> client_master_key: SSL2ClientMasterKey(self.length, sh);
SSL2ProtocolMessages::ssl_server_verify -> : skip bytes &size=self.length;
SSL2ProtocolMessages::ssl_request_certificate -> : skip bytes &size=self.length;
SSL2ProtocolMessages::ssl_client_certificate -> : skip bytes &size=self.length;
} if(get_encrypted(sh) == False) ;
: skip bytes &size=self.length if(get_encrypted(sh) == True);
on %done { on %done {
msg.first_packet = False; msg.first_packet = False;
} }
on %init {
if (sh.negotiated_version != UNKNOWN_VERSION && sh.negotiated_version != SSLv2) {
spicy::decline_input("Late switch to SSLv2 record");
}
}
};
type SSL2ClientMasterKey = unit(length: uint16, inout sh: Share) {
: skip bytes &size=length;
on %init {
sh.client_encrypted = True;
sh.server_encrypted = True;
sh.established = True;
zeek::skip_input();
}
}; };
# For TLS-y protocols - determine how to continue # For TLS-y protocols - determine how to continue
@ -777,7 +800,6 @@ type PlaintextRecord = unit(content_type: uint8, handshakesink: sink&, alertsink
* -> unhandled: skip bytes &size=self.length; * -> unhandled: skip bytes &size=self.length;
}; };
trigger_two: void; trigger_two: void;
trigger_three: void;
on length { on length {
self.encrypted = determine_encryption_on(self, content_type, handshakesink, alertsink, sh); self.encrypted = determine_encryption_on(self, content_type, handshakesink, alertsink, sh);
@ -797,7 +819,7 @@ type PlaintextRecord = unit(content_type: uint8, handshakesink: sink&, alertsink
startEncryption(handshakesink, alertsink, sh); startEncryption(handshakesink, alertsink, sh);
} }
on trigger_two { on trigger_two {
if (sh.both_sides_encrypted_first_time) if (sh.both_sides_encrypted_first_time && content_type != 20)
sh.both_sides_encrypted_first_time = False; sh.both_sides_encrypted_first_time = False;
} }
}; };
@ -965,16 +987,13 @@ type uint24 = unit {
type SSL2ClientHello = unit(len: uint64, msg: Message, inout sh: Share) { type SSL2ClientHello = unit(len: uint64, msg: Message, inout sh: Share) {
direction_check: DirectionCheck(sh, True); # should be sent by originator direction_check: DirectionCheck(sh, True); # should be sent by originator
client_version: uint16; client_version: uint16;
csuite_len: uint16; ciphers_len: uint16;
session_len: uint16; session_len: uint16;
chal_len: uint16; chal_len: uint16;
ciphers: uint24[self.csuite_len / 3]; ciphers: uint24[self.ciphers_len / 3];
session_id: bytes &size=self.session_len; session_id: bytes &size=self.session_len;
challenge: bytes &size=self.chal_len; challenge: bytes &size=self.chal_len;
# to make the event easier
compression_methods: uint8[0];
on client_version { on client_version {
if (self.client_version != SSLv2 && self.client_version != SSLv3 && self.client_version != TLSv10 && self.client_version != TLSv11 && self.client_version != TLSv12) { if (self.client_version != SSLv2 && self.client_version != SSLv3 && self.client_version != TLSv10 && self.client_version != TLSv11 && self.client_version != TLSv12) {
spicy::decline_input("Invalid version in SSL client hello. Version: %s, self.client_version"); # Version: " + self.client_version); spicy::decline_input("Invalid version in SSL client hello. Version: %s, self.client_version"); # Version: " + self.client_version);
@ -989,6 +1008,34 @@ type SSL2ClientHello = unit(len: uint64, msg: Message, inout sh: Share) {
} }
}; };
type SSL2ServerHello = unit(len: uint64, msg: Message, inout sh: Share) {
direction_check: DirectionCheck(sh, False); # should be sent by responder
session_id_hit: uint8 &requires=($$ < 2);
certificate_type: uint8 &requires=($$ == 1); # X509 certificate
server_version: uint16 &requires=($$ == 2); # Has to be version 2, everything else uses new server hello format
cert_len: uint16;
ciphers_len: uint16;
conn_id_len: uint16;
cert_data: bytes &size=self.cert_len;
ciphers: uint24[self.ciphers_len / 3];
conn_id_data: bytes &size=self.conn_id_len;
on %init {
if (msg.first_packet == False) {
spicy::decline_input("SSLv2 server hello late in connection");
}
}
on %done {
sh.chosen_version_sh_outer = self.server_version;
set_version(self.server_version, sh);
zeek::file_begin("application/x-x509-user-cert", get_certificate_fuid(get_direction(sh), get_and_increase_certificate_depth(sh)));
zeek::file_data_in(self.cert_data);
zeek::file_end();
}
};
type ClientHello = unit(len: uint64, msg: Message, inout sh: Share) { type ClientHello = unit(len: uint64, msg: Message, inout sh: Share) {
direction_check: DirectionCheck(sh, True); # should be sent by originator direction_check: DirectionCheck(sh, True); # should be sent by originator
client_version: uint16; client_version: uint16;
@ -1915,6 +1962,14 @@ public function check_direction(inout sh: Share, desired: bool): bool {
return False; return False;
} }
on SSL::SSL2ClientHello::%done {
spicy::accept_input();
}
on SSL::SSL2ServerHello::%done {
spicy::accept_input();
}
on SSL::ClientHello::%done { on SSL::ClientHello::%done {
spicy::accept_input(); spicy::accept_input();
} }

View file

@ -1,6 +1,3 @@
# Does not work in spicy version, due to missing SSLv2 handshake support
# @TEST-REQUIRES: ! grep -q "#define ENABLE_SPICY_SSL" $BUILD/zeek-config.h
# @TEST-EXEC: zeek -C -b -r $TRACES/tls/ssl-v2.trace %INPUT # @TEST-EXEC: zeek -C -b -r $TRACES/tls/ssl-v2.trace %INPUT
# @TEST-EXEC: zeek -b -r $TRACES/tls/ssl.v3.trace %INPUT # @TEST-EXEC: zeek -b -r $TRACES/tls/ssl.v3.trace %INPUT
# @TEST-EXEC: zeek -b -r $TRACES/tls/tls1.2.trace %INPUT # @TEST-EXEC: zeek -b -r $TRACES/tls/tls1.2.trace %INPUT