7

Usually, people recommend to use a single private-public key pair everywhere (if we're not talking about a possibility of compromising the private key):

  1. Best Practice: “One per-user ssh key” or “multiple per-host ssh keys”
  2. Reusing Private/Public Keys
  3. https://serverfault.com/questions/80478/ssh-do-you-use-one-private-public-key-pair-for-each-remote-machine-or-a-single/80483#80483

    It seems that this would result in a vulnerability when using client certificate authentication over SSH. Since it is so popular to suggest, I suspect the "algorithm" below won't work. But I just don't get what exactly is wrong with it.

I've tried to make my description as detailed as possible, to minimize possible discrepancies, so, please excuse me for the length...

Preconditions

  • PC1 has both (S1_id_rsa.pub and S2_id_rsa.pub) fingerprints in his known hosts.
  • Server1 somehow knows about existence of PC1's account on Server2.
  • Keys:
    • PC1 : has P1_id_rsa , S1_id_rsa.pub, S2_id_rsa.pub.
    • Server1, the attacker : has S1_id_rsa, P1_id_rsa.pub, S2_id_rsa.pub.
    • Server2: has S2_id_rsa, P1_id_rsa.pub

Algorithm

This is something like a well-known man-in-the-middle attack, but a bit different.

  1. PC1 sends "Hi" to Server1
  2. Server1 sends "Hi" to Server2
  3. Server shares it's public key

    1. Server2 sends Server1 S2_id_rsa.pub
    2. Server1 sends PC1 S1_id_rsa.pub (instead of S2_id_rsa.pub)
    3. PC1 accepts S1_id_rsa.pub's fingerprint (as it's known)
  4. Two separate shared-secret tunnels are generated using Diffie-Hellman:

    1. "Server1--Server2"

      1. Server2 generates DH1.a, and sends DH1.A,signed with S2_id_rsa, to Server1
      2. Server1 generates DH1.b and sends DH1.B to Server2
      3. Tunnel established
    2. "PC1--Server1"
      1. Server1 generates DH2.a, and sends DH1.A, signed with S1_id_rsa, to PC1
      2. PC1 generates DH2.b and sends DH2.B to Server1
      3. Tunnel is established.
  5. Client Authentication (Server2 now wants to be sure he is talking to PC1)

    1. PC1 sends P1_id_rsa.pub to Server1
    2. Server1 sends P1_id_rsa.pub to Server2
    3. Server2 generates a challenge, which could be solved only with P1_id_rsa and sends it to Server1
    4. Server1 just tunnels challenge to PC1
    5. PC1 solves the challenge and sends answer to Server1
    6. Server1 tunnels answer to Server2
    7. Done.
  6. Done

P.S. I've looked through public-key cryptography and man-in-the-middle attack on Wikipedia, and this quite detailed answer (my view of the whole process is largely based on it), but I've not found the answer..

I wasn't able to find a readable "complete ssh authentication and encryption processes for dummies"...

I've already asked the same question on Server Fault, but was suggested to re-post it here.

Igor
  • 201
  • 2
  • 8
  • Note that if you login to a rouge server with SSH agent forwarding enabled, and the SSH key available in your agent without verification, the rouge server can use this to log in into a different server, using a similar scheme as you described. – Paŭlo Ebermann Aug 23 '16 at 17:21

4 Answers4

3

Usually, people recommend to use a single private-public key pair everywhere (if we're not talking about a possibility of compromising the private key)

Note that there are two key pairs involved in an SSH connection:

  • one to identify the server host (the server has the private key);
  • one to identify the user (the client has the private key), if using public key authentication.

The recommendations you cite are about user keys. Having a single private key per user is a viable model, though I don't particularly recommend it (the cost of having separate key pairs per host or site isn't that high). Server keys, on the other hand, are never duplicated. They are generated afresh when the SSH server is installed.

On this topic, beyond the posts you've cited in your question, see also What is the difference between authorized_keys and known_hosts file for SSH?

In the attack you describe, you've mixed up the roles of the keys. These are the host keys, ssh_host_rsa, and not user keys. This isn't directly relevant in how the attack you describe works, but may be part of your confusion.

The sticky point is at step 3.3:

PC1 accepts S1_id_rsa.pub's fingerprint (as it's known)

There are two cases.

  • If PC1 has connected to S2 before, then PC1 (or more precisely the account of the user on PC1) has memorized S2's host public key in its known_hosts file. So if S1 sends S2's host key, the SSH client on PC1 will detect that the purported host key does not match the recorded host key and abort the connection with a scary message:

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
    Someone could be eavesdropping on you right now (man-in-the-middle attack)!
    It is also possible that the RSA host key has just been changed.
    

    The attack is thus impossible in this scenario (unless the user goes out of his way to bypass the check — OpenSSH purposefully makes this difficult).

  • If PC1 has never connected to S2, then PC1 will happily accept whatever S1 is now telling it is S2's key. Since PC1 has no prior knowledge of any association between the name S2 and a cryptographic identity, nor any way to contact a trusted third party who knows such an association (i.e. a public-key infrastructure), there is no way to prevent this man-in-the-middle attack.

Gilles 'SO- stop being evil'
  • 51,955
  • 14
  • 122
  • 182
  • Note that there are two key pairs involved in an SSH connection

    There might be a slight confusion in the naming scheme: I've just named 'Server2\etc\ssh\ssh_host_rsa_key.pub' "S2_id_rsa.pub", and "S1_id_rsa.pub" is defined in the same manner. 2)

    If PC1 has connected to S2 before, then PC1 (or more precisely the account of the user on PC1) has memorized S2's host public key in its known_hosts file

    Em... The thing is, in my algorithm , Server1 provides PC1 with S1_id_rsa.pub, not S2<..>.pub

    – Igor Jan 21 '13 at 22:23