GH-1264: Implement "ssh_server_host_key" event

This event provides host key fingerprints for both SSH1 and SSH2.
This commit is contained in:
Jon Siwek 2020-11-13 21:48:29 -08:00
parent 93469d811d
commit bd40a97a78
8 changed files with 97 additions and 16 deletions

View file

@ -138,6 +138,34 @@ event ssh2_server_host_key%(c: connection, key: string%);
## ssh2_gss_error ssh2_ecc_key
event ssh1_server_host_key%(c: connection, p: string, e: string%);
## During the :abbr:`SSH (Secure Shell)` key exchange, the server
## supplies its public host key. This event is generated when the
## appropriate key exchange message is seen for SSH1 or SSH2 and provides
## a fingerprint of the server's host key.
##
## c: The connection over which the :abbr:`SSH (Secure Shell)`
## connection took place.
##
## hash: an MD5 hash fingerprint associated with the server's host key.
## For SSH2, this is the hash of the "server public host key" string as
## seen on the wire in the Diffie-Hellman key exchange reply message
## (the string itself, excluding the 4-byte length associated with it),
## which is also the *key* parameter of :zeek:see:`ssh2_server_host_key`
## For SSH1, this is the hash of the combined multiprecision integer
## strings representing the RSA1 key's prime modulus and public exponent
## (concatenated in that order) as seen on the wire,
## which are also the parameters of :zeek:see:`ssh1_server_host_key`.
## In either case, the hash is the same "fingerprint" string as presented
## by other traditional tools, ``ssh``, ``ssh-keygen``, etc, and is the
## hexadecimal representation of all 16 MD5 hash bytes delimited by colons.
##
## .. 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_encrypted_packet ssh2_dh_server_params
## ssh2_gss_error ssh2_ecc_key
event ssh_server_host_key%(c: connection, hash: string%);
## This event is generated when an :abbr:`SSH (Secure Shell)`
## encrypted packet is seen. This event is not handled by default, but
## is provided for heuristic analysis scripts. Note that you have to set

View file

@ -2,10 +2,12 @@
#include <cstdlib>
#include <vector>
#include <string>
#include "zeek/digest.h"
%}
%header{
zeek::VectorValPtr name_list_to_vector(const bytestring& nl);
const char* fingerprint_md5(const unsigned char* d);
%}
%code{
@ -45,6 +47,14 @@ zeek::VectorValPtr name_list_to_vector(const bytestring& nl)
}
return vv;
}
const char* fingerprint_md5(const unsigned char* d)
{
return zeek::util::fmt("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
}
%}
refine flow SSH_Flow += {
@ -153,6 +163,17 @@ refine flow SSH_Flow += {
connection()->zeek_analyzer()->Conn(),
to_stringval(${key}));
}
if ( ssh_server_host_key )
{
unsigned char digest[MD5_DIGEST_LENGTH];
zeek::detail::internal_md5(${key}.data(), ${key}.length(), digest);
zeek::BifEvent::enqueue_ssh_server_host_key(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
zeek::make_intrusive<zeek::StringVal>(fingerprint_md5(digest)));
}
return true;
%}
@ -165,6 +186,23 @@ refine flow SSH_Flow += {
to_stringval(${p}),
to_stringval(${e}));
}
if ( ssh_server_host_key )
{
unsigned char digest[MD5_DIGEST_LENGTH];
auto ctx = zeek::detail::hash_init(zeek::detail::Hash_MD5);
// Note: the 'p' and 'e' parameters actually have swapped meanings with
// 'p' actually being the exponent.
// Fingerprint is calculated over concatenation of modulus + exponent.
zeek::detail::hash_update(ctx, ${e}.data(), ${e}.length());
zeek::detail::hash_update(ctx, ${p}.data(), ${p}.length());
zeek::detail::hash_final(ctx, digest);
zeek::BifEvent::enqueue_ssh_server_host_key(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
zeek::make_intrusive<zeek::StringVal>(fingerprint_md5(digest)));
}
return true;
%}