Brute Force SSH Attack Protection

This HOWTO describes a couple things that you can do to secure your SSH server on a Linux machine (Ubuntu, RedHat, Suse...).

This is useful because there are script kiddies all around trying to break into computers. And I imagine that botnets writers will take more interest in Linux as it's market share increases.

The pattern that I have seen is of many many requests from the same IP address trying to guess users and passwords. Most of the requests are trying to guess the root password.

There are a couple things we can do to slow these attackers. The most obvious is to configure ssh to only allow logins from a couple select users. And to disallow remote login by the root user. We can also use IPTables to only allow a limited number of connections per minute. And finaly, we can move the SSH server to a different port on the machine. I don't know if this actually causes the attackers any pause however. They may just be trying all of the open ports.

There are more complex solutions to the problem. Port knocking or log parsing come to mind. But I've opted for the simplest solution that doesn't impact usability in my case.

The use of IPTables to limit repeated connections is based on work by Kevin van Zonneveld. You can see his approach on his blog

What is IPTables

IPTables is part of the kernels network stack (I think). It is a user configurable state machine that can be used to filter packets as they are received, before they are forwarded or before they are transmitted.

Our configuration will drop incoming packets that meet a specific set of rules.

SSHD configuration

The file /etc/ssh/sshd_config is used to configure the ssh server on your linux machine. The changes I made to mine were to change "Port 22" to "Port xxxx" and to add "AllowUsers yyyy zzzz wwww" where xxxx is the new port you want SSH to listen to. yyyy, zzzz and wwww are the users that you want to have remove access. I also made sure that the line "PermitRootLogin no" existed and was not commented out.

SSH configuration

If you have changed the port that sshd listens to then you will probably want to configure your ssh clients on any machine that you would like to access your server from. In your home directory on each of these machines you should find "~/.ssh/". In that directory you can create a config file. It's just called config. Put the following in that file. Again, xxxx is the new port that your ssh server is listening to.

Host your.server.name
Port xxxx

Network scripts

In Ubuntu there are directories that contain scripts to run when an interface comes up or goes down. These are convenient places to put the IPTables commands needed to drop attackers packets. The directory for scripts to run when a network interface comes up is /etc/network/if-up.d. And the directory for scripts to run when a network interface goes down is /etc/network/if-down.d. We will create one file in the if-up.d directory and a symlink in the if-down.d directory. We do this to consolidate the logic in a single location. We can use the MODE variable to determine if the interface is coming up or going down.

In /etc/network/if-up.d/ssh-protection put the following.

#!/bin/bash

SSH_IFACE="eth1"
SSH_PORT=xxxx   # This should be the port you've moved your ssh server to, or 22 if you haven't moved it.
SSH_PERIOD=60
SSH_COUNT=8

#
# Only add the rules to the interface that SSH is actually listening on.
#
if [ "$IFACE" != "$SSH_IFACE" ]; then
    exit 0
fi

case "$MODE" in
    start)
        IPTABLES_ACTION="-A"
        ;;

    stop)
        IPTABLES_ACTION="-D"
        ;;
esac

/sbin/iptables $IPTABLES_ACTION INPUT \
               -i $IFACE \
               -p tcp \
               --dport $SSH_PORT \
               -m state \
               --state NEW \
               -m recent \
               --set \
               --name SSH
/sbin/iptables $IPTABLES_ACTION INPUT \
               -i $IFACE \
               -p tcp \
               --dport $SSH_PORT \
               -m state \
               --state NEW \
               -m recent \
               --update \
               --seconds $SSH_PERIOD \
               --hitcount $SSH_COUNT \
               --rttl \
               --name SSH \
               -j DROP

This file needs to be executable by root. You can use the following command line to make it so.

chmod u+x /etc/network/if-up.d/ssh-protection

And in /etc/network/if-down.d create a symlink to the ssh-protection file in if-up.d using the following command line. This command line assumes you're in the if-down.d directory.

ln -s ../if-up.d/ssh-protection