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.