2013-08-12

Have SSH prompt your users twice for their password

The SSH service is a vital part of IT management operations. However, keeping intruders out while allowing password authentication can be a pretty hard challenge. In this scenario, passwords are usually the weakest link: since security and convenience run in opposite directions, misinformed users will always look for some way to improve convenience at the cost of "a little" security. That's where they choose weak passwords that can be easily guessed by brute force.

Brute-force guessing passwords is a simple challenge that's mostly time-bound. The attacker typically tries every one from a list of common passwords until they are allowed into the target system. Failed passwords don't allow the attacker to tell whether they got only two or ten characters wrong. The easier to guess the password, the earlier it appears in the attacker's list. And the quicker the attacker can try another password, the quicker they reach the correct one.

Stalling the attacker with a short interval before they are allowed to enter a new password seems like a good plan, but the password guessing attack can be easily parallelized. A much better alternative is to ask your users to enter their password twice: the unknowing attacker will never try the same password twice in a row — why would they? — so even a password of "123" could keep them out, while attackers who know about this strategy will at least be stalled.

This post explains how to implement this strategy on Red Hat Enterprise Linux 6.x systems. For that, all you need to do is edit the /etc/ssh/sshd_config and /etc/pam.d/sshd files.

sshd_config

OpenSSH is a flexible daemon. It can perform password authentication with or without talking to PAM (Pluggable Authentication Modules). By default, Red Hat Enterprise Linux 6.x will enable sshd's use of PAM (UsePAM yes on /etc/ssh/sshd_config) for password authentication, which is part of what you'll need. It will also enable password authentication (PasswordAuthentication yes on the same file) and disable challenge-response authentication (ChallengeResponseAuthentication no, same file), which is the opposite of what's needed to ask the user to enter the password twice. So, first of all you will need to change these settings:

#/etc/ssh/sshd_config
...
PasswordAuthentication no
...
ChallengeResponseAuthentication yes
...

(Documentation on sshd_config(5))

PAM configuration

The file controlling PAM's behavior when authenticating SSH users on Red Hat Enterprise Linux 6.x is /etc/pam.d/sshd and it looks like this by default:

#%PAM-1.0
auth       required     pam_sepermit.so
auth       include      password-auth
account    required     pam_nologin.so
...

This means that when sshd asks PAM to authenticate a user, PAM will first consult the pam_sepermit.so module, which checks the /etc/security/sepermit.conf file for users who should be allowed or denied authentication access by SELinux (pam_sepermit(8)). Then, PAM will open the /etc/pam.d/password-auth and read all lines starting with auth in order to know what to check next.

The /etc/pam.d/password-auth file looks like this:

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required     pam_env.so
auth        sufficient   pam_unix.so nullok try_first_pass
auth        requisite    pam_succeed_if.so uid >= 500 quiet
auth        required     pam_deny.so
...

These auth lines mean that PAM will use the pam_env.so module to set and unset environment variables defined in /etc/security/pam_env.conf (pam_env(8)). After that, the pam_unix.so module will perform the traditional password checks, i.e. /etc/shadow when using local files (pam_unix(8)), and PAM will consider this sufficient to authenticate the user.

If you duplicate the pam_unix.so line and change PAM's view of this check to required instead of sufficient, you will effectively ask PAM to check the traditional authentication sources twice.

Note, however, that the comments in /etc/pam.d/password-auth state that this file is auto-generated and that "changes will be destroyed the next time authconfig is run". Additionally, this file is used by many other programs and daemons when authenticating users and changing it would alter the behavior of authentication for all those other programs and daemons.

The only safe path is to copy the auth lines from this file to sshd's specific file, i.e. /etc/pam.d/sshd, and comment out the line that called /etc/pam.d/password-auth. This is what you get:

# /etc/pam.d/sshd
#%PAM-1.0
auth       required     pam_sepermit.so
# auth       include      password-auth
# The following lines have come from the password-auth file
auth       required     pam_env.so
auth       sufficient   pam_unix.so nullok try_first_pass
auth       requisite    pam_succeed_if.so uid >= 500 quiet
auth       required     pam_deny.so
# End of lines coming from password-auth

account    required     pam_nologin.so
...

Now you can duplicate the pam_unix.so line and ask PAM to require this check to pass before it is tested a second time:

# /etc/pam.d/sshd
#%PAM-1.0
auth       required      pam_sepermit.so
# auth       include       password-auth
# The following lines have come from the password-auth file
auth       required      pam_env.so
auth       required      pam_unix.so nullok try_first_pass
auth       sufficient    pam_unix.so nullok try_first_pass
auth       requisite     pam_succeed_if.so uid >= 500 quiet
auth       required      pam_deny.so
# End of lines coming from password-auth

account    required      pam_nologin.so
...

You are almost there. If you try to ssh to this machine right now, you'll only be prompted for the password once. That's because the try_first_pass argument to the pam_unix.so module tells the sufficient line to try the password that has just been given, which defeats the purpose of the duplicate password prompt.

So, remove the try_first_pass argument from the second line to make it actually ask for the password a second time:

# /etc/pam.d/sshd
#%PAM-1.0
auth       required      pam_sepermit.so
# auth       include       password-auth
# The following lines have come from the password-auth file
auth       required      pam_env.so
auth       required      pam_unix.so nullok try_first_pass
auth       sufficient    pam_unix.so nullok
auth       requisite     pam_succeed_if.so uid >= 500 quiet
auth       required      pam_deny.so
# End of lines coming from password-auth

account    required      pam_nologin.so
...

That's it. Try to ssh to the target system and check if everything goes as planned. Feel free to use ssh -v (repeated v's for more verbosity) if something goes wrong.

Further stalling the attacker

As the attacker may come prepared to try every single password twice, you can at least stall them by running /usr/bin/sleep 2 between password prompts. PAM allows you to do this with the pam_exec.so module (pam_exec(8)). Your /etc/pam.d/sshd file should then look like this:

# /etc/pam.d/sshd
#%PAM-1.0
auth       required      pam_sepermit.so
# auth       include       password-auth
# The following lines have come from the password-auth file
auth       required      pam_env.so
auth       required      pam_unix.so nullok try_first_pass
auth       optional      pam_exec.so quiet /usr/bin/sleep 2
auth       sufficient    pam_unix.so nullok
auth       requisite     pam_succeed_if.so uid >= 500 quiet
auth       required      pam_deny.so
# End of lines coming from password-auth

account    required      pam_nologin.so
...

Now your system is ready to offer the convenience of password authentication with reduced a risk of giving in to brute-force attacks.