diff --git a/scripts/base/protocols/ssh/main.bro b/scripts/base/protocols/ssh/main.bro index 2ac289750a..bba3f8ac88 100644 --- a/scripts/base/protocols/ssh/main.bro +++ b/scripts/base/protocols/ssh/main.bro @@ -1,7 +1,5 @@ ##! Implements base functionality for SSH analysis. Generates the ssh.log file. -# Generated by binpac_quickstart - module SSH; export { @@ -14,20 +12,33 @@ export { uid: string &log; ## The connection's 4-tuple of endpoint addresses/ports. id: conn_id &log; + ## Auth result + result: string &log &optional; + ## Auth method (password, pubkey, etc.) + method: string &log &optional; + ## Direction of the connection. If the client was a local host + ## logging into an external host, this would be OUTBOUND. INBOUND + ## would be set for the opposite situation. + ## TODO: handle local-local and remote-remote better. + direction: Direction &log &optional; ## The client's version string client: string &log &optional; ## The server's version string server: string &log &optional; ## The server's key fingerprint host_key: string &log &optional; - ## Auth result - result: string &log &optional; - ## Auth method (password, pubkey, etc.) - method: string &log &optional; + ## This connection has been logged (internal use) + logged: bool &default=F; }; + ## If true, we tell the event engine to not look at further data + ## packets after the initial SSH handshake. Helps with performance + ## (especially with large file transfers) but precludes some + ## kinds of analyses. + const skip_processing_after_detection = F &redef; + ## Event that can be handled to access the SSH record as it is sent on - ## to the loggin framework. + ## to the logging framework. global log_ssh: event(rec: Info); } @@ -43,6 +54,24 @@ event bro_init() &priority=5 Analyzer::register_for_ports(Analyzer::ANALYZER_SSH, ports); } +function determine_auth_method(middle_pkt_len: int, first_pkt_len: int): string + { + # This is still being tested. + # Based on "Analysis for Identifying User Authentication Methods on SSH Connections" + # by Satoh, Nakamura, Ikenaga. + + if ( middle_pkt_len == 96 ) + return "password"; + if ( middle_pkt_len == 16 ) + return "gssapi"; + if ( ( middle_pkt_len == 32 ) && ( first_pkt_len == 0 || first_pkt_len == 48 ) ) + return "challenge-response"; + if ( middle_pkt_len < 256 ) + return fmt("unknown (mid=%d, first=%d)", middle_pkt_len, first_pkt_len); + if ( first_pkt_len == 16 ) + return "host-based"; + return fmt("pubkey (~%d bits)", (first_pkt_len - 16)*8); + } event ssh_server_version(c: connection, version: string) { @@ -70,46 +99,74 @@ event ssh_client_version(c: connection, version: string) c$ssh$client = version; } -function determine_auth_method(middle_pkt_len: int, first_pkt_len: int): string - { - if ( middle_pkt_len == 96 ) - return "password"; - if ( ( middle_pkt_len == 32 ) && ( first_pkt_len == 0 || first_pkt_len == 48 ) ) - return "challenge-response"; - if ( ( first_pkt_len >= 112 ) && ( first_pkt_len <= 432 ) ) - return "pubkey"; - if ( first_pkt_len == 16 ) - return "host-based"; - return fmt("unknown (mid=%d, first=%d)", middle_pkt_len, first_pkt_len); - } - event ssh_auth_successful(c: connection, middle_pkt_len: int, first_pkt_len: int) { + print "ssh_auth_successful"; if ( !c?$ssh || ( c$ssh?$result && c$ssh$result == "success" ) ) return; c$ssh$result = "success"; c$ssh$method = determine_auth_method(middle_pkt_len, first_pkt_len); - Log::write(SSH::LOG, c$ssh); } +event ssh_auth_successful(c: connection, middle_pkt_len: int, first_pkt_len: int) &priority=-5 + { + c$ssh$logged = T; + Log::write(SSH::LOG, c$ssh); + } + event ssh_auth_failed(c: connection, middle_pkt_len: int, first_pkt_len: int) { + print "ssh_auth_failed"; if ( !c?$ssh || ( c$ssh?$result && c$ssh$result == "success" ) ) return; c$ssh$result = "failure"; c$ssh$method = determine_auth_method(middle_pkt_len, first_pkt_len); + } + +event ssh_auth_failed(c: connection, middle_pkt_len: int, first_pkt_len: int) &priority=-5 + { + c$ssh$logged = T; Log::write(SSH::LOG, c$ssh); } -event connection_closed(c: connection) +event connection_state_remove(c: connection) { if ( c?$ssh && !c$ssh?$result ) { c$ssh$result = "unknown"; - Log::write(SSH::LOG, c$ssh); } } +event ssh_server_capabilities(c: connection, kex_algorithms: string, server_host_key_algorithms: string, encryption_algorithms_client_to_server: string, encryption_algorithms_server_to_client: string, mac_algorithms_client_to_server: string, mac_algorithms_server_to_client: string, compression_algorithms_client_to_server: string, compression_algorithms_server_to_client: string, languages_client_to_server: string, languages_server_to_client: string) + { + # print "kex_algorithms", kex_algorithms; + # print ""; + # print "server_host_key_algorithms", server_host_key_algorithms; + # print ""; + # print "encryption_algorithms_client_to_server", encryption_algorithms_client_to_server; + # print ""; + # print "encryption_algorithms_server_to_client", encryption_algorithms_server_to_client; + # print ""; + # print "mac_algorithms_client_to_server", mac_algorithms_client_to_server; + # print ""; + # print "mac_algorithms_server_to_client", mac_algorithms_server_to_client; + # print ""; + # print "compression_algorithms_client_to_server", compression_algorithms_client_to_server; + # print ""; + # print "compression_algorithms_server_to_client", compression_algorithms_server_to_client; + # print ""; + # print "languages_client_to_server", languages_client_to_server; + # print ""; + # print "languages_server_to_client", languages_server_to_client; + # print ""; + } + +event connection_state_remove(c: connection) &priority=-5 + { + if ( c?$ssh && !c$ssh$logged ) + Log::write(SSH::LOG, c$ssh); + } + event ssh_server_host_key(c: connection, key: string) { if ( !c?$ssh ) diff --git a/src/analyzer/protocol/ssh/SSH.cc b/src/analyzer/protocol/ssh/SSH.cc index 1d942c5097..c6ac74f5dc 100644 --- a/src/analyzer/protocol/ssh/SSH.cc +++ b/src/analyzer/protocol/ssh/SSH.cc @@ -91,12 +91,12 @@ void SSH_Analyzer::ProcessEncrypted(int len, bool orig) relative_len = len - initial_client_packet_size; else relative_len = len - initial_server_packet_size; - if ( num_encrypted_packets_seen >= 4 ) + + if ( num_encrypted_packets_seen >= 6 ) { int auth_result = AuthResult(relative_len, orig); if ( auth_result > 0 ) { - num_encrypted_packets_seen = 1; if ( auth_result == 1 ) BifEvent::generate_ssh_auth_successful(interp->bro_analyzer(), interp->bro_analyzer()->Conn(), packet_n_1_size, packet_n_2_size); @@ -105,28 +105,35 @@ void SSH_Analyzer::ProcessEncrypted(int len, bool orig) packet_n_1_size, packet_n_2_size); } } - if ( num_encrypted_packets_seen >= 2 ) + if ( ( num_encrypted_packets_seen >= 2 ) && + ( orig != packet_n_1_is_orig ) ) { packet_n_2_is_orig = packet_n_1_is_orig; packet_n_2_size = packet_n_1_size; } - packet_n_1_is_orig = orig; - packet_n_1_size = relative_len; - num_encrypted_packets_seen++; + + if ( orig == packet_n_1_is_orig ) + packet_n_1_size += len; + else + { + packet_n_1_is_orig = orig; + packet_n_1_size = relative_len; + num_encrypted_packets_seen++; + } } int SSH_Analyzer::AuthResult(int len, bool orig) { - if ( !orig && packet_n_1_is_orig && !packet_n_2_is_orig ) + if ( !orig && packet_n_1_is_orig && !packet_n_2_is_orig ) { + printf("Auth result = %d\n", len); if ( len == -16 ) return 1; - else if ( len >= 16 && - len <= 32 ) + else if ( len >= 16 && len <= 32 ) return 2; return 0; } - return -1; + return -1; } diff --git a/src/analyzer/protocol/ssh/ssh-analyzer.pac b/src/analyzer/protocol/ssh/ssh-analyzer.pac index 05cf20d4b4..e4dd71bc39 100644 --- a/src/analyzer/protocol/ssh/ssh-analyzer.pac +++ b/src/analyzer/protocol/ssh/ssh-analyzer.pac @@ -60,10 +60,6 @@ refine typeattr SSH_DH_GEX_REPLY += &let { proc: bool = $context.flow.proc_ssh_server_host_key(k_s.val); }; -refine typeattr SSH_DH_GEX_GROUP += &let { - proc: bool = $context.flow.proc_ssh_server_host_key(p.val); -}; - refine typeattr SSH_Message += &let { proc_newkeys: bool = $context.flow.proc_newkeys() &if(msg_type == SSH_MSG_NEWKEYS); }; \ No newline at end of file diff --git a/src/analyzer/protocol/ssh/ssh-protocol.pac b/src/analyzer/protocol/ssh/ssh-protocol.pac index aea112ff10..03f47fd67a 100644 --- a/src/analyzer/protocol/ssh/ssh-protocol.pac +++ b/src/analyzer/protocol/ssh/ssh-protocol.pac @@ -5,37 +5,37 @@ enum state { }; enum message_id { - SSH_MSG_DISCONNECT = 1, - SSH_MSG_IGNORE = 2, - SSH_MSG_UNIMPLEMENTED = 3, - SSH_MSG_DEBUG = 4, - SSH_MSG_SERVICE_REQUEST = 5, - SSH_MSG_SERVICE_ACCEPT = 6, - SSH_MSG_KEXINIT = 20, - SSH_MSG_NEWKEYS = 21, - SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30, - SSH_MSG_KEX_DH_GEX_GROUP = 31, - SSH_MSG_KEX_DH_GEX_INIT = 32, - SSH_MSG_KEX_DH_GEX_REPLY = 33, - SSH_MSG_KEX_DH_GEX_REQUEST = 34, - SSH_MSG_USERAUTH_REQUEST = 50, - SSH_MSG_USERAUTH_FAILURE = 51, - SSH_MSG_USERAUTH_SUCCESS = 52, - SSH_MSG_USERAUTH_BANNER = 53, - SSH_MSG_GLOBAL_REQUEST = 80, - SSH_MSG_REQUEST_SUCCESS = 81, - SSH_MSG_REQUEST_FAILURE = 82, - SSH_MSG_CHANNEL_OPEN = 90, - SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91, - SSH_MSG_CHANNEL_OPEN_FAILURE = 92, - SSH_MSG_CHANNEL_WINDOW_ADJUST = 93, - SSH_MSG_CHANNEL_DATA = 94, - SSH_MSG_CHANNEL_EXTENDED_DATA = 95, - SSH_MSG_CHANNEL_EOF = 96, - SSH_MSG_CHANNEL_CLOSE = 97, - SSH_MSG_CHANNEL_REQUEST = 98, - SSH_MSG_CHANNEL_SUCCESS = 99, - SSH_MSG_CHANNEL_FAILURE = 100, + SSH_MSG_DISCONNECT = 1, + SSH_MSG_IGNORE = 2, + SSH_MSG_UNIMPLEMENTED = 3, + SSH_MSG_DEBUG = 4, + SSH_MSG_SERVICE_REQUEST = 5, + SSH_MSG_SERVICE_ACCEPT = 6, + SSH_MSG_KEXINIT = 20, + SSH_MSG_NEWKEYS = 21, + SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30, + SSH_MSG_KEX_DH_GEX_GROUP = 31, + SSH_MSG_KEX_DH_GEX_INIT = 32, + SSH_MSG_KEX_DH_GEX_REPLY = 33, + SSH_MSG_KEX_DH_GEX_REQUEST = 34, + SSH_MSG_USERAUTH_REQUEST = 50, + SSH_MSG_USERAUTH_FAILURE = 51, + SSH_MSG_USERAUTH_SUCCESS = 52, + SSH_MSG_USERAUTH_BANNER = 53, + SSH_MSG_GLOBAL_REQUEST = 80, + SSH_MSG_REQUEST_SUCCESS = 81, + SSH_MSG_REQUEST_FAILURE = 82, + SSH_MSG_CHANNEL_OPEN = 90, + SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91, + SSH_MSG_CHANNEL_OPEN_FAILURE = 92, + SSH_MSG_CHANNEL_WINDOW_ADJUST = 93, + SSH_MSG_CHANNEL_DATA = 94, + SSH_MSG_CHANNEL_EXTENDED_DATA = 95, + SSH_MSG_CHANNEL_EOF = 96, + SSH_MSG_CHANNEL_CLOSE = 97, + SSH_MSG_CHANNEL_REQUEST = 98, + SSH_MSG_CHANNEL_SUCCESS = 99, + SSH_MSG_CHANNEL_FAILURE = 100, }; type SSH_PDU(is_orig: bool) = case $context.connection.get_state(is_orig) of {