System-wide:
/etc/ssh/known_hosts

User scoped:
~/.ssh/known_hosts

Overview

When an SSH connection is being established, the server sends its public host key to the client and proves knowledge of the associated private host key. The host keys are generally generated upon the installation of the SSH service and are used for server-side authentication of the SSH server.

The OpenSSH client stores the public host key of hosts that were previously accessed. These keys, called “known host keys”, are stored in the known_hosts text-based files. The known_hosts file can be system-wide (/etc/ssh/known_hosts) or user scoped (~/.ssh/known_hosts).

The system-wide known_hosts file can be optionally manually set by a system administrator, while the user scoped known_hosts file is automatically populated by the SSH client. The client indeed add an entry to the per-user file upon the first access to a given SSH server and host key pair, following the user validation of the server authenticity (through its public host key fingerprint).

The ssh-keyscan(1) utility to can be used to collect the public SSH host key of the specified host to manually add it to the known_hosts files:

# To add the REMOTE_HOST public key to the known_hosts system-wide.

ssh-keyscan -H -t rsa <REMOTE_HOST> >> /etc/ssh/ssh_known_hosts

If the legitimacy of the public host key was validated upon the first connection, the known_hosts files can be used to establish the trust with the remote server in subsequent access in order to protect against man-in-the-middle network attacks. If the public host key of a known host changes, the SSH client will display an alert.

The known_hosts is one of the few endpoint disk artefacts to identify outgoing SSH connections.

Information of interest

The known_hosts files are plaintext files, with (generally) one known host information per line.

Each line contains the following fields: the hostname(s), the public host key type (ssh-rsa, ssh-ed25519, ecdsa-sha2-nistp256, …), the base64-encoded public host key, and an optional comment. The fields are separated by spaces. An older format stores the public host key’s bits, exponent, and modulus (separated by spaces) instead of the base64-encoded public host key.

The hostname(s) is a single pattern or a comma-separated list of patterns. A pattern can be a hostname or an IP address, with * and ? acting as wildcards.

Example of known_hosts entries:

# Entry referencing the known host through "server_hostname" and its IP address 10.0.0.10.
server_hostname,10.0.0.10 ssh-rsa AAAA12[...]KXIOz

# Entry with a (single) hashed known host.
|1|9dM[...]/NZ4U= ssh-rsa AAAAB3Nza[...]D02jEM=

Hashed known hosts

The remote hosts hostname and IP address can be either stored in clear-text or hashed if HashKnownHosts is set to “yes” in the SSH client ssh_config configuration file. Only one hashed hostname may appear on a single line. The lines containing an hashed hostname start with |1|.

Even if the hosts information are hashed, the following command can be used to check whether the specified hostname is present in the given known hosts file:

ssh-keygen -l -f <KNOWN_HOST_FILE> -F <HOSTNAME>

Additionally, John the Ripper can be used to brute force known hosts files, using for instance the private IP address ranges:

known_host_file=<KNOWN_HOST_FILE>

john --format=known_hosts $known_host_file

nmap -sL -Pn -n 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 | grep '^Nmap scan report for' | cut -d ' ' -f 5 > IP_list.txt

john --wordlist=IP_list.txt --format=known_hosts $known_host_file

References



View on GitHub