If you own a Linux server (for example Ubuntu on Digital Ocean), you need to take care of brute force attacks coming via SSH.

During the last year with my current IP address, there were attempts from 67 IP addresses trying to log in brute-force via SSH against root and various other user names. Services such as CloudFlare can help to prevent attacks coming through HTTP protocol, but not through SSH, coming directly into your IP address.

Here’s how to prevent that.

Enter iptables

iptables is a low-level Linux firewall. If you block a visitor’s IP address there, the server will refuse to serve it (completely). Now the question becomes, how to effectively identify hackers’ IP addresses and add them to iptables. This is done using log2iptables script.

Log2iptables

Every event in Linux is logged. We need a script that runs periodically (through Linux cron), reads the Linux system logs and looks for failed login attempts. If failed login entry is found, the script would add hacker’s IP address to iptables banned IP list.

Log2iptables setup tutorial

  1. Go to log2iptables on GitHub and copy down the contents of this shell script. Save the copy somewhere. We will need to edit it a bit.
  2. Find a row which says:

        LIMIT=5;
        
    

    That’s how many failed login attempts should result to ban. I set it to 3. Keep in mind; you can get banned yourself if you wrongly type your password too many times. That’s why I run the script with LIMIT=1 manually.

  3. Change IPTABLESEXEC=0; to IPTABLESEXEC=1;. This turns off the testing mode.

  4. Search for rows:

    biniptables=$(which iptables);
    bingrep=$(which grep);
    binwc=$(which wc);
    bincurl=$(which curl);
    bincolumn=$(which column);
    binsendmail=$(which sendmail);
    shostname=$(hostname);
    sallipadd=$(hostname --all-ip-addresses);
    

    Those rows are querying the system variables, but I found that it doesn’t work when the script is launched through CRON. Therefore, you have to run all those queries above manually, in your terminal, while logged in to your server, then set them as fixed values in your script.

    For example, look at biniptables=$(which iptables);. The command we need to replace is which iptables. In the command line, run which iptables. Console responds with /sbin/iptables. Put it into a row as: biniptables="/sbin/iptables";

    Do the same for all lines above.

    Here’s my setup from a live server (IP was changed):

    biniptables="/sbin/iptables";
    bingrep="/bin/grep";
    binwc="/usr/bin/wc";
    bincurl="/usr/bin/curl";
    bincolumn="/usr/bin/column";
    binsendmail="/usr/sbin/sendmail";
    shostname="codeandsend.com";
    sallipadd="111.222.333.444";
    
  5. Let’s create a script file on the server and place our edited script’s content.

    We’ll place the script in /usr/local/bin/log2iptables.sh.

    Open the location:

    cd /usr/local/bin/
    
  6. Create an empty file:

    sudo touch log2iptables.sh
    
  7. Open it with Nano text editor:

    sudo nano log2iptables.sh
    
  8. Paste all the script you edited locally there.

  9. Close the file by pressing CTRL+X, then confirm thanges with “Y”.

  10. Confirm the system logs are stored in /var/log/auth.log.

    Open the location:

    cd /var/log/
    

    Above is the location for Ubuntu 14.04 LS, but it might be different on a different system.

  11. Open the auth.log:

    sudo nano auth.log
    

    If you see log entries there, you are all set. If you can’t find auth.log, use Google and StackOverflow until you locate where your logs are being saved.

  12. First, try manually running our shell script:

    sudo /usr/local/bin/log2iptables.sh
    
  13. If the script worked OK, let’s add it to the CRON:

    Open Cron:

    sudo crontab -e
    
  14. Add line at the bottom:

    */10 * * * * /usr/local/bin/log2iptables.sh >/dev/null 2>&1
    

    ‘*/10’ means the script will run every 10 minutes. The end part >/dev/null 2>&1 prevents system from sending you an email after a successful run. It will just be silent.

What to do if you got IP-banned from your own server

Log in to Digital Ocean admin panel; it has a console, which is equivalent to plugging a physical keyboard to your server. It will be an offer to the server it can’t refuse (using Godfather terminology).

Find your IP address.

wget http://ipinfo.io/ip -qO -

Delete your IP from iptables (replace it with your IP from the above):

sudo iptables -D INPUT -s 61.76.168.121 -j DROP

Testing log2iptables

To test, review what’s in iptables first:

sudo iptables -nL -v --line-numbers

If you delete the entry from your iptables, run the log2iptables script (manually or, ideally, by waiting >10 minutes) and see that the particular IP got added again, this means system worked.

You can delete entries from iptables by row:

sudo iptables -D INPUT 2

Or by IP:

sudo iptables -D INPUT -s 61.76.168.121 -j DROP

You can tell did the particular IP existed in the iptables or not from the deletion command result — if you try to delete the IP that doesn’t exist, system will show error message.

Troubleshooting

It cost me few days to find out why log2iptables was working fine when called manually, but not when called on schedule via the ‘crontab’. It’s because cron can’t execute the calls to system variables. The following won’t work on cron:

biniptables=$(which iptables);

You need to run the which iptables part manually and place the result as string:

biniptables="/sbin/iptables";

Same goes with any rows that have $() calls in the log2iptables script. You have to replace them all.

You should note that Ubuntu archives the old logs, so if you see auth.log.2.gz, auth.log.3.gz and so on in logs folder /var/log/, this means you have to ungzip them and run the script on each.

Running the log2iptables manually

It’s also possible to run the log2iptables manually. It is useful when you want to try different strictness settings (like LIMIT=5;) or different log files.

For example:

Limit failed login attempt count to 1:

sudo /usr/local/bin/log2iptables.sh -x 1 -f /var/log/auth.log -p 3 -l 1

-l 1 flag sets the login attempt limit to 1.

Don’t change -p 3 (it is almost a ‘system’ variable, setting IP Address group number) or -x 1 (tells the script to execute the command instead of merely testing it).