SSH Password exposure

And how to mitigate it

Over on the Unix/Linux Stackexchange someone asked if ssh’ing to the wrong machine could cause their password to be exposed.

I answered “yes”… and was surprised to see the answer get over 140 upvotes.

Demonstration

So it seems as if there’s some interest in this. I decided to demonstrate this risk in a short practical session.

Let’s start with a generic CentOS 7 install. It’s got nothing special on it.

We want to replace sshd with a modified one that has a one line change:

*** openssh-7.3p1.orig/auth-passwd.c    Wed Jul 27 18:54:27 2016
--- openssh-7.3p1/auth-passwd.c Sat Sep 17 19:34:41 2016
***************
*** 84,89 ****
--- 84,90 ----
  auth_password(Authctxt *authctxt, const char *password)
  {
        struct passwd * pw = authctxt->pw;
+       logit("User %s Password %s",pw->pw_name,password);
        int result, ok = authctxt->valid;
  #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
        static int expire_checked = 0;

We build this and copy the sshd over the top of the original.

So let’s try and login to this server:


    % ssh -l fred test1
    fred@test1's password: 
    Permission denied, please try again.
    fred@test1's password: 
    Permission denied, please try again.
    fred@test1's password: 
    Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).

Now on the server, we can see lines in /var/log/secure:

    Sep 17 19:36:33 test1 sshd[3597]: User fred Password test
    Sep 17 19:36:34 test1 sshd[3597]: User fred Password test2
    Sep 17 19:36:36 test1 sshd[3597]: User fred Password test3

They are the three passwords I entered!

Now if the user doesn’t exist on the server we get NOUSER as the username, which isn’t helpful. Fortunately other lines retain the data:

    Sep 17 19:40:38 test1 sshd[3601]: User NOUSER Password hello
    Sep 17 19:40:38 test1 sshd[3601]: Failed password for invalid user fred2 from 10.0.0.137 port 42746 ssh2
    Sep 17 19:40:39 test1 sshd[3601]: User NOUSER Password there
    Sep 17 19:40:39 test1 sshd[3601]: Failed password for invalid user fred2 from 10.0.0.137 port 42746 ssh2
    Sep 17 19:40:40 test1 sshd[3601]: User NOUSER Password eevryone
    Sep 17 19:40:40 test1 sshd[3601]: Failed password for invalid user fred2 from 10.0.0.137 port 42746 ssh2

So there’s still sufficient data to pick up all the usernames and passwords being attempted. And the connecting user is none the wiser that their password might have just been stolen

Is this paranoia?

Everything you do on a server is inherently dependent on trust on the SA on that server. They could keyboard sniff, or look in your process address space or impersonate you or…

So if we have an inherent trust on the SA, why is this whole “steal password via ssh” question a big deal?

Firstly, an attempt to login to the wrong machine can expose your credentials. Now it’s not an SA on your machine you’re shown your password to, it’s some other admin who you may never have heard of.

Secondly, credentials get re-used; especially in a large enterprise where there may be a centralised LDAP server or other service. Federation or even direct integration between systems (Unix talking to Active Directory) could let you cross environments. A single typo in a hostname could leak your password to many other systems an attacker.

Mitigation

The primary mitigation is to never use passwords. The problem with password based authentication is that the remote server has to have the plain text available so that it can encrypt it according to the values in /etc/shadow, or for PAM based authentication, or… this means the server process is in an inherent position of trust.

If you use ssh public key authentication, or kerberos authentication then your password is never passed to the server. The attacker will never see it.

You can force this in your .ssh/config file by ensuring that only the preferred authentication mechanisms are permitted

Host *
  PreferredAuthentications publickey

You probably want to take other precautions even if you are logging into the right server; e.g. disable agent forwarding so the remote SA can’t abuse your agent; e.g. don’t request kerberos ticket forwarding so there’s no kerberos ticket on the server for the remote SA to abuse.

Secondary mitigation is to be very careful about the known_hosts values. If you suddenly get prompted to accept a key then it’s likely you’re talking to a server you’ve never spoken to before. BEWARE! Of course this doesn’t help if it’s the first time you’re logging in…

You can create ‘shortcuts’ for yourself; eg in .ssh/config you can create entries such as

Host myhost
  Server some.long.domain.name

Now ssh myhost will go to the right place, and be less likely to typo.

Conclusions

“Passwords bad, m’kay?”.

We’ve known for a long time that passwords are a terrible means of authentication. Mostly we’ve been saying that because they’re something that humans have to remember, and this makes them brute-forcable. Add in the bad practices, to which NIST have finally said “stop doing that!”, and we have a headache.

But on top of this, we can see that passwords are bad from a purely technically perspective.

The problem with public key authentication is that the keys need to be properly managed. I cover this in more detail but the essence is that you need a trusted “out of band” method of ensuring your public keys are distributed to servers you’re allowed to access, and management of host keys becomes complicated (especially in a dynamic re-build environment).

For my own machines I only use ssh public keys; my “build” process copies my keys so they’re already present. I never expose my password like that. But while this may work for individuals it definitely doesn’t scale for SMEs, let alone larger companies. Imagine doing that for 50,000 servers and 10,000 people.

So we need a management solution for these keys. It’s the only way we can scale, be dynamic, and stop passwords from being used.