Or cat-ing some secrets that would be on target machine but not attacker
To be frank, anyone that serious about security would probably log in via console, generate and retrieve the host key that way. And then any client would have strict verification enabled.
It's kinda the 101 of communication using public keys cryptography. You have to get hold of the public key in a secure manner first (direct contact or attestation by a third party).
Section 3.1 in Bruce Scheiner's Applied Cryptography discuss how to automatically solves MITM. But that's only important for M:N communications (TSL). For 1:1 communications where you can have secure exchange before hand, no need to go that far.
A big way to deter them is to keep remote log files which, if analyzed, will reveal any attack.
For example, if both ssh-client and ssh-server kept a fingerprint of the session key in some append-only logfile, then a later administrator could compare the logfiles to know if an MITM happened.
Suddenly, nation state attackers won't be interested in MITM-ing at all.
Unfortunately it appears openssh doesn't even have an option to create such a logfile!! Why not??
It's a neat little trick if you're often deploying VPS in shared cloud environments.
If so, the legitimate server wouldn’t have anything in their logs that would help detect such an attack.
OpenSSH does log other telemetry though.
How to deploy secrets during bootstrap to a new virtual machine running in the Cloud that does not leave a trace in the infrastructure. And in a way that I can completely automate the deployment.
One answer is providing the secrets in cloudinit - but this leaves a trail on the host/provider's infrastructure, I do not know if those configs I paste into the portal then get saved off somewhere.
The other option (more secure) is having the keys/secrets generated on the host itself at first boot. But then this is difficult to automate as I would need to scrap them (even just the public parts) in a secure way. One option would be to have the public keys printed to the terminal/VNC - but this is much more trouble than it is worth to automate.
I'm not sure on a good solution. This is taking quite an adversarial security model though, assuming the host/provider is not completely trustworthy. Of course not owning the hardware means that the host/provider could be performing other attacks without my knowledge (copying memory, etc.)
2. Use certificates and your own CA.
3. Use the virtual serial console for first login.
4. Use cloudinit to add a custom software repo, then use that to install a custom package that does the initial work.
Fingerprints are derived from the certificates/private keys. Unless I don't understand some basic crypto, or SSH works in some obtuse way, I do not think it would be possible for the MITM attacker to present the server with the true client's fingerprint unless they also had had the client's private key.
This little script stops attacks on the first SSH connection to a new VM, even on providers (like Hetzner Cloud) that don't offer a proprietary solution; we only need cloud-init, which is widely supported.
Summary (for experts; read on for a longer explanation): inject a temporary SSH host (private) key via cloud-init, and trust that temporary SSH host key just long enough to generate and retrieve the "real" (long-term) SSH host keys. The script is a simple but hardened implementation of this technique; the comments in the script discuss implementation choices. The technique appears to be new: I haven't found a proper write-up of this, nor of any other provider-independent solution (but I'd welcome a correction).
This technique actually protects the first connection, whereas just answering "yes" when ssh asks "The authenticity of host [...] can't be established" (i.e. Trust On First Use) leaves you open to an attacker rerouting your traffic to a proxy, or to an attacker generously deciding to provide your VM (... for now).
This technique also makes leaks of the cloud-init userdata harmless. Injecting a long-term SSH host (private) key via cloud-init does allow you to authenticate the first connection (by adding the public part of the injected key to ~/.ssh/known_hosts), but leaves valuable (private) key material in the cloud-init userdata, where an attacker can often obtain it from
the metadata service, which any process on the VM can typically read; e.g. on a Hetzner VM:
$ curl http://169.254.169.254/hetzner/v1/userdata
#cloud-config
ssh_keys:
ecdsa_private: |
-----BEGIN OPENSSH PRIVATE KEY-----
[...]
-----END OPENSSH PRIVATE KEY-----
ecdsa_public: ecdsa-sha2-nistp256 AAAAE2Vj[...]tI= temporary host key for [...]
An attacker can often trick some process into divulging this data via SSRF (which is often not blocked, even where the provider does offer a solution); or from
the provider's (other) systems (e.g. Hetzner explicitly warns against storing "passwords or other sensitive information"); or from
your administrator workstation.
Throughout, we trust the (Open)SSH protocol and implementation, and we do not rely on you, the administrator, detecting the attack.
We protect
against an attacker
because the attacker never learns any key material at a time when it is still valuable.
To prevent accidental use of the temporary SSH host key, the script keeps it in a temporary directory; the temporary SSH host key is never in ~/.ssh/known_hosts.
We protect
against an attacker
because the (long-term) SSH host (private) key was never on the administrator workstation, and because the attacker does not actually connect to the VM.
(An attacker who does connect to the VM will likely be able to learn the SSH host key, e.g. via ssh root@<VM> cat /etc/ssh/ssh_host_*.)
We protect
against an attacker
because we assume (Open)SSH is secure.
As an additional safeguard for this scenario, the script does not just write output from the VM to ~/.ssh/known_hosts, but relies on OpenSSH key rotation to place the long-term SSH host keys there, which
ssh's known_hosts parser, and~/.ssh/known_hosts that the VM actually controls, andHashKnownHosts (and any relevant options that might be added in the future).It depends. In particular, the attacker likely fails if you actually detect that all your connections are, and always have been, to the wrong machine, and cannot be convinced to enter a password (on the first or on any later connection), and don't configure ssh to forward an agent or X11 connection.
As a simplified non-exhaustive list, with thanks to ssh-mitm,
The attacker may instead/additionally succeed at attacking your workstation if you use any authentication method and forward an X11 connection.