Added several events for detailed info on the SSH2 key init directions

This commit is contained in:
Joost Jansen 2022-12-02 11:27:25 +01:00
parent dbbb6cd6f0
commit bcdbca4bb9
8 changed files with 178 additions and 18 deletions

View file

@ -100,7 +100,8 @@ event ssh_auth_attempted%(c: connection, authenticated: bool%);
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh2_server_host_key ssh1_server_host_key
## ssh_server_host_key ssh_encrypted_packet ssh2_dh_server_params
## ssh2_gss_error ssh2_ecc_key
## ssh2_gss_error ssh2_ecc_key ssh2_ecc_init ssh2_dh_gex_init
## ssh2_rsa_secret ssh2_gss_init
event ssh_capabilities%(c: connection, cookie: string, capabilities: SSH::Capabilities%);
## During the :abbr:`SSH (Secure Shell)` key exchange, the server
@ -171,7 +172,8 @@ event ssh1_server_host_key%(c: connection, modulus: string, exponent: string%);
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_encrypted_packet ssh2_dh_server_params
## ssh2_gss_error ssh2_ecc_key
## ssh2_gss_error ssh2_ecc_key ssh2_ecc_init ssh2_dh_gex_init
## ssh2_gss_init ssh2_rsa_secret
event ssh_server_host_key%(c: connection, hash: string%);
## This event is generated when an :abbr:`SSH (Secure Shell)`
@ -211,7 +213,7 @@ event ssh_encrypted_packet%(c: connection, orig: bool, len: count%);
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_gss_error ssh2_ecc_key
## ssh2_gss_error ssh2_dh_gex_init
event ssh2_dh_server_params%(c: connection, p: string, q: string%);
## In the event of a GSS-API error on the server, the server MAY send
@ -231,7 +233,7 @@ event ssh2_dh_server_params%(c: connection, p: string, q: string%);
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_ecc_key
## ssh2_dh_server_params ssh2_ecc_key ssh2_gss_init
event ssh2_gss_error%(c: connection, major_status: count, minor_status: count, err_msg: string%);
## The :abbr:`ECDH (Elliptic Curve Diffie-Hellman)` and
@ -251,5 +253,72 @@ event ssh2_gss_error%(c: connection, major_status: count, minor_status: count, e
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_gss_error
## ssh2_dh_server_params ssh2_gss_error ssh2_ecc_init
event ssh2_ecc_key%(c: connection, is_orig: bool, q: string%);
## The :abbr:`ECDH (Elliptic Curve Diffie-Hellman)` and
## :abbr:`ECMQV (Elliptic Curve Menezes-Qu-Vanstone)` key exchange
## algorithms use two ephemeral key pairs to generate a shared
## secret. This event is generated when either the SSH_MSG_KEX_ECDH_INIT
## or SSH_MSG_ECMQV_INIT message is observed. By definition, these need
## to originate from the client and not from the server.
## For more information, see:
## :rfc:`5656#section-4`.
##
## c: The connection
##
## is_orig: Did this message come from the originator?
##
## .. zeek:see:: ssh_server_version ssh_client_version
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_gss_error ssh2_ecc_key
event ssh2_ecc_init%(c: connection, is_orig: bool%);
## Generated if the connection uses a Diffie-Hellman Group Exchange
## key exchange method. This event contains the direction of the key
## exchange setup, which is indicated by the the SSH_MSG_KEX_DH_GEX_INIT
## message as defined in :rfc:`4419#section-3`.
##
## c: The connection
##
## is_orig: Did this message come from the originator?
##
## .. zeek:see:: ssh_server_version ssh_client_version
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_gss_error
event ssh2_dh_gex_init%(c: connection, is_orig: bool%);
## In the event of a GSS-API key exchange, this event is raised on
## SSH_MSG_KEXGSS_INIT message.
## For more information see :rfc:`4462#section-2.1`.
##
## c: The connection
##
## is_orig: Did this message come from the originator?
##
## .. zeek:see:: ssh_server_version ssh_client_version
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_gss_error
event ssh2_gss_init%(c: connection, is_orig: bool%);
## In the event of a GSS-API key exchange, this event is raised on
## SSH_MSG_KEXRSA_PUBKEY message. This message is sent first by the server,
## after which the server will respond with a SSH_MSG_KEXRSA_SECRET message.
## For more information see :rfc:`4432#section-4`.
##
## c: The connection
##
## is_orig: Did this message come from the originator?
##
## .. zeek:see:: ssh_server_version ssh_client_version
## ssh_auth_successful ssh_auth_failed ssh_auth_result
## ssh_auth_attempted ssh_capabilities ssh2_server_host_key
## ssh1_server_host_key ssh_server_host_key ssh_encrypted_packet
## ssh2_dh_server_params ssh2_gss_error
event ssh2_rsa_secret%(c: connection, is_orig: bool%);

View file

@ -120,6 +120,50 @@ refine flow SSH_Flow += {
return true;
%}
function proc_ssh2_ecc_init(is_orig: bool): bool
%{
if ( ssh2_ecc_init )
{
zeek::BifEvent::enqueue_ssh2_ecc_init(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
is_orig);
}
return true;
%}
function proc_ssh2_dh_gex_init(is_orig: bool): bool
%{
if ( ssh2_dh_gex_init )
{
zeek::BifEvent::enqueue_ssh2_dh_gex_init(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
is_orig);
}
return true;
%}
function proc_ssh2_gss_init(is_orig: bool): bool
%{
if ( ssh2_gss_init )
{
zeek::BifEvent::enqueue_ssh2_gss_init(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
is_orig);
}
return true;
%}
function proc_ssh2_rsa_secret(is_orig: bool): bool
%{
if ( ssh2_rsa_secret )
{
zeek::BifEvent::enqueue_ssh2_rsa_secret(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
is_orig);
}
return true;
%}
function proc_ssh2_dh_gex_group(msg: SSH2_DH_GEX_GROUP): bool
%{
@ -257,11 +301,24 @@ refine typeattr SSH2_DH_GEX_GROUP += &let {
refine typeattr SSH2_ECC_REPLY += &let {
proc_k: bool = $context.flow.proc_ssh2_server_host_key(k_s.val);
proc_q: bool = $context.flow.proc_ssh2_ecc_key(q_s.val, false);
proc_q: bool = $context.flow.proc_ssh2_ecc_key(q_s.val, is_orig);
};
refine typeattr SSH2_ECC_INIT += &let {
proc: bool = $context.flow.proc_ssh2_ecc_key(q_c.val, true);
proc: bool = $context.flow.proc_ssh2_ecc_key(q_c.val, is_orig);
proc_init: bool = $context.flow.proc_ssh2_ecc_init(is_orig);
};
refine typeattr SSH2_DH_GEX_INIT += &let {
proc_init: bool = $context.flow.proc_ssh2_dh_gex_init(is_orig);
};
refine typeattr SSH2_GSS_INIT += &let {
proc_init: bool = $context.flow.proc_ssh2_gss_init(is_orig);
};
refine typeattr SSH2_RSA_SECRET += &let {
proc_init: bool = $context.flow.proc_ssh2_rsa_secret(is_orig);
};
refine typeattr SSH1_PUBLIC_KEY += &let {

View file

@ -130,7 +130,7 @@ type SSH2_KEXINIT(length: uint32, is_orig: bool) = record {
# KEX_DH exchanges
type SSH2_Key_Exchange_DH_Message(is_orig: bool, msg_type: uint8, length: uint32) = case msg_type of {
SSH_MSG_KEXDH_INIT -> init : SSH2_DH_GEX_INIT(length);
SSH_MSG_KEXDH_INIT -> init : SSH2_DH_GEX_INIT(length, is_orig);
SSH_MSG_KEXDH_REPLY -> reply : SSH2_DH_GEX_REPLY(length);
default -> unknown: bytestring &length=length &transient;
};
@ -141,7 +141,7 @@ type SSH2_Key_Exchange_DH_GEX_Message(is_orig: bool, msg_type: uint8, length: ui
SSH_MSG_KEX_DH_GEX_REQUEST_OLD -> request_old : SSH2_DH_GEX_REQUEST_OLD;
SSH_MSG_KEX_DH_GEX_REQUEST -> request : SSH2_DH_GEX_REQUEST;
SSH_MSG_KEX_DH_GEX_GROUP -> group : SSH2_DH_GEX_GROUP(length);
SSH_MSG_KEX_DH_GEX_INIT -> init : SSH2_DH_GEX_INIT(length);
SSH_MSG_KEX_DH_GEX_INIT -> init : SSH2_DH_GEX_INIT(length, is_orig);
SSH_MSG_KEX_DH_GEX_REPLY -> reply : SSH2_DH_GEX_REPLY(length);
default -> unknown : bytestring &length=length &transient;
};
@ -161,7 +161,7 @@ type SSH2_DH_GEX_GROUP(length: uint32) = record {
g : ssh_string;
} &length=length;
type SSH2_DH_GEX_INIT(length: uint32) = record {
type SSH2_DH_GEX_INIT(length: uint32, is_orig: bool) = record {
e : ssh_string;
} &length=length;
@ -175,7 +175,7 @@ type SSH2_DH_GEX_REPLY(length: uint32) = record {
type SSH2_Key_Exchange_RSA_Message(is_orig: bool, msg_type: uint8, length: uint32) = case msg_type of {
SSH_MSG_KEXRSA_PUBKEY -> pubkey : SSH2_RSA_PUBKEY(length);
SSH_MSG_KEXRSA_SECRET -> secret : SSH2_RSA_SECRET(length);
SSH_MSG_KEXRSA_SECRET -> secret : SSH2_RSA_SECRET(length, is_orig);
SSH_MSG_KEXRSA_DONE -> done : SSH2_RSA_DONE(length);
};
@ -184,7 +184,7 @@ type SSH2_RSA_PUBKEY(length: uint32) = record {
k_t : ssh_string;
} &length=length;
type SSH2_RSA_SECRET(length: uint32) = record {
type SSH2_RSA_SECRET(length: uint32, is_orig: bool) = record {
encrypted_payload : ssh_string;
} &length=length;
@ -195,7 +195,7 @@ type SSH2_RSA_DONE(length: uint32) = record {
# KEX_GSS exchanges
type SSH2_Key_Exchange_GSS_Message(is_orig: bool, msg_type: uint8, length: uint32) = case msg_type of {
SSH_MSG_KEXGSS_INIT -> init : SSH2_GSS_INIT(length);
SSH_MSG_KEXGSS_INIT -> init : SSH2_GSS_INIT(length, is_orig);
SSH_MSG_KEXGSS_CONTINUE -> cont : SSH2_GSS_CONTINUE(length);
SSH_MSG_KEXGSS_COMPLETE -> complete : SSH2_GSS_COMPLETE(length);
SSH_MSG_KEXGSS_HOSTKEY -> hostkey : SSH2_GSS_HOSTKEY(length);
@ -204,7 +204,7 @@ type SSH2_Key_Exchange_GSS_Message(is_orig: bool, msg_type: uint8, length: uint3
SSH_MSG_KEXGSS_GROUP -> group : SSH2_DH_GEX_GROUP(length);
};
type SSH2_GSS_INIT(length: uint32) = record {
type SSH2_GSS_INIT(length: uint32, is_orig: bool) = record {
output_token : ssh_string;
e : ssh_string;
} &length=length;
@ -237,19 +237,19 @@ type SSH2_GSS_ERROR(length: uint32) = record {
# KEX_ECDH and KEX_ECMQV exchanges
type SSH2_Key_Exchange_ECC_Message(is_orig: bool, msg_type: uint8, length: uint32) = case msg_type of {
SSH_MSG_KEX_ECDH_INIT -> init : SSH2_ECC_INIT(length);
SSH_MSG_KEX_ECDH_REPLY -> reply : SSH2_ECC_REPLY(length);
SSH_MSG_KEX_ECDH_INIT -> init : SSH2_ECC_INIT(length, is_orig);
SSH_MSG_KEX_ECDH_REPLY -> reply : SSH2_ECC_REPLY(length, is_orig);
};
# This deviates from the RFC. SSH_MSG_KEX_ECDH_INIT and
# SSH_MSG_KEX_ECMQV_INIT can be parsed the same way.
type SSH2_ECC_INIT(length: uint32) = record {
type SSH2_ECC_INIT(length: uint32, is_orig: bool) = record {
q_c : ssh_string;
};
# This deviates from the RFC. SSH_MSG_KEX_ECDH_REPLY and
# SSH_MSG_KEX_ECMQV_REPLY can be parsed the same way.
type SSH2_ECC_REPLY(length: uint32) = record {
type SSH2_ECC_REPLY(length: uint32, is_orig: bool) = record {
k_s : ssh_string;
q_s : ssh_string;
signature : ssh_string;

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
Detected an ECC INIT not from the TCP client

View file

@ -0,0 +1,12 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event
Found SSH2_DH_GEX_INIT event

Binary file not shown.

View file

@ -0,0 +1,12 @@
# @TEST-EXEC: zeek -b -Cr $TRACES/ssh/reverse-ssh.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
@load base/protocols/ssh
event ssh2_ecc_init(c: connection, is_orig: bool) {
## If a machine sends out the initial key material for the handshake, this should come from the client.
## In most cases, this client is the machine that set up the TCP connection.
if ( ! is_orig ) {
print("Detected an ECC INIT not from the TCP client");
}
}

View file

@ -0,0 +1,8 @@
# @TEST-EXEC: zeek -b -Cr $TRACES/ssh/sshguess.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
@load base/protocols/ssh
event ssh2_dh_gex_init(c: connection, is_orig: bool) {
print("Found SSH2_DH_GEX_INIT event");
}