Home » Defense in Depth

Mitigating SSH Brute Force Attacks

Posted 1 Jan 2007 | Comments Off on Mitigating SSH Brute Force Attacks | 2,864 views

Occassionaly, users require remote access to a server to gain shell access or upload files. If your users are accessing the server from known IP addresses, your job is easy. You can simply restrict SSH access to those IP addresses using an iptables ruleset and hosts.allow entries. (You are practicing defense in depth, right?) The problem arises when your users will not be accessing your server from predetermined source addresses. Unfortunately, allowing global SSH access to your server opens your server up to brute force password attacks.

If you currently allow global SSH access, your logfiles are probably filled with hundreds (possibly thousands) of entries similar to the following:

Jan 1 08:43:10 myserver sshd(pam_unix)[6191]: authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost= user=root

The account that everyone wants is root, and the root account should never be directly accessible. In /etc/ssh/sshd_config, block direct SSH access for root by setting the following directive:

PermitRootLogin no

Now that the root account is blocked, let’s work on the other accounts. Brute force attacks are typically targetted against common system accounts (ie apache, mysql, etc) using dictionaries of passwords. At the very minimum, the repeated attempts tie up system resources. In the worst case, an account is compromised. The non-root also need to be protected. In the sshd_config file, separate the list of user into those that should and should not have SSH access:

AllowUsers peter paul mary
DenyUsers daemon bin sys man lp mail nobody apache mysql

We can use PAM to further restrict which accounts will be accessible. Insert the following line to the beginning of /etc/pam.d/ssh:

auth required pam_listfile.so sense=allow item=user file=/etc/ssh/allowed_users onerr=fail

Create /etc/ssh/allowed_users with one account per line. Avoid putting any role or shared accounts in this file.


Restart sshd, and only accounts that are listed in the file will be able to login. No other accounts will be able to login even if the correct password is supplied. It may seem like overkill listing the allowed accounts in two places, but this is a good defense in depth strategy.

So far we haven’t done anything to address the brute force password attacks. We’ve simply restricted which accounts can login. At this point, each user needs to generate a SSH key pair on their client computer and place their public key in the authorized_keys file on the remote server. Insist that they place a password on their private key.

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/paul/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):********
Enter same passphrase again:********
Your identification has been saved in /home/paul/.ssh/id_rsa.
Your public key has been saved in /home/paul/.ssh/id_rsa.pub.
The key fingerprint is:
f7:ed:63:ab:02:bb:96:34:7d:b3:a7:69:4f:0b:fe:ed paul@localhost
$ scp ~/.ssh/id_rsa.pub paul@remoteserver:~/.ssh/authorized_keys

Going back to /etc/ssh/sshd_config, we make the following change and restart:

PasswordAuthentication no

Now all allowed users are required to login using their private key. The authentication sequence will fail for any non-matching key pair.

The number of attempts can be limited with a simple iptables ruleset. The rule allowing global SSH access probably looks similar to the following:

-A INPUT -p tcp –dport 22 -i eth0 -m state –state NEW -j ACCEPT

A better ruleset would allow known networks and throttle the rest. This can be done by replacing the line above with something similar to:

-A INPUT -p tcp -s –dport 22 -i eth0 -m state –state NEW -j ACCEPT
-A INPUT -p tcp –dport 22 -i eth0 -m state –state NEW -m recent –set
-A INPUT -p tcp –dport 22 -i eth0 -m state –state NEW -m recent –update –seconds 60 –hitcount 4 -j DROP

In short, we are allowing anyone on the local network unfettered access with a SSH key pair. Everyone else is limited to three connections (–hitcount 4) per minute (–seconds 60), and they are still required to use a key.

Public/private keys and SSH throttling is a good compromise to allowing SSH access from any location. The key pairs are considerably more complex than simple passwords, and the throttling limits the amount of system resources. Your users can login from anywhere, and you can be fairly confident the the successful login was not from an automated tool.

Comments are closed.