Virtual Brain Online Logo

Bookmark: Root \ Linux \ How to protect your Linux server from SSH brute force attacks


Last Updated: 2010-08-04

Have you ever looked at your ssh log and noticed all the unauthorized login attempts?

Note: I am doing this on a CentOS 5 server so the log file paths might be different on your system. If you send me the name of your distro, version and paths I will add them to this page.

Here is an example of my log file which is located in

  • CentOS 5 => /var/loge/secure
  • ARCH => /var/log/auth.log

Mar 28 14:48:19 srv-2of9 sshd[30532]: Invalid user oracle from 202.130.103.70
Mar 28 14:48:19 srv-2of9 sshd[30538]: input_userauth_request: invalid user oracle
Mar 28 14:48:19 srv-2of9 sshd[30537]: Invalid user oracle from 202.130.103.70
Mar 28 14:48:19 srv-2of9 sshd[30540]: input_userauth_request: invalid user oracle
Mar 28 14:48:19 srv-2of9 sshd[30538]: Received disconnect from 202.130.103.70: 11: Bye Bye
Mar 28 14:48:19 srv-2of9 sshd[30540]: Received disconnect from 202.130.103.70: 11: Bye Bye
Mar 28 14:48:21 srv-2of9 sshd[30556]: Invalid user test from 202.130.103.70
Mar 28 14:48:21 srv-2of9 sshd[30563]: input_userauth_request: invalid user test
Mar 28 14:48:21 srv-2of9 sshd[30560]: Invalid user test from 202.130.103.70
Mar 28 14:48:21 srv-2of9 sshd[30566]: input_userauth_request: invalid user test
Mar 28 14:48:21 srv-2of9 sshd[30563]: Received disconnect from 202.130.103.70: 11: Bye Bye
Mar 28 14:48:21 srv-2of9 sshd[30566]: Received disconnect from 202.130.103.70: 11: Bye Bye

As you can see my server is under brute force attack from 202.130.103.70. The log is full of login attempts where the attacker is attempting all kinds of username and password combinations. So I wanted a way to stop this.
First I started to write a short PHP script to parse /var/log/secure, count the invalid connection attempts and prepare an iptables script. While researching the best way to implement the custom rules created by my script I came across the recent option of the match module.

The recent option allows the firewall to automatically block a connection after it has detected too many new connection attempts from an ip. So instead of having to run a log parser I implemented the SSH brute force blocker with these simple iptables commands.

#SSH anti brute force
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 600 --hitcount 5 --rttl --name SSH -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Yes that is all it takes and this is how it works. iptables tracks every new connection on port 22. When some one from the same IP connects 5 times within 600 seconds the IP will be automatically banned for 600 seconds. You can adjust these condition yourself by modifying --hitcount and –seconds.

In addition to the above you should also change your sshd configuration to only allow one login attempt per connection. I think the default is three attempts so with the above rule an attacker could try 12 logins before getting banned instead of 4.
Edit the file sshd config file and modify or add the line:
  • CentOS => /etc/ssh/sshd_config
  • ARCH => /etc/ssh/sshd_config
MaxAuthTries 1

That is it and the difference is noticable just by looking at the size of the log file before and after the new rule has been added.
# ls -lh secure*
-rw------- 1 root root 2.1K Apr 18 08:31 secure
-rw------- 1 root root 35K Apr 18 04:27 secure.1
-rw------- 1 root root 583K Apr 11 04:27 secure.2 <= Added the rule here
-rw------- 1 root root 3.0M Apr 4 04:27 secure.3
-rw------- 1 root root 2.3M Mar 28 04:27 secure.4

Here are a few more things you might want to know.
  • The list of blocked IPs can be found in the /proc/net/ipt_recent/ directory. The directory contains one file per -- set --name option (first rule).
    • CentOS => /proc/net/ipt_recent/
    • ARCH => /proc/net/xt_recent/
  • You can add an IP to the SSH list with this command
    echo xx.xx.xx.xx > /proc/net/ipt_recent/SSH
  • This will remove an entry from the SSH list
    echo -xx.xx.xx.xx > /proc/net/ipt_recent/SSH
  • And this will clear the entire list
    echo clear > /proc/net/ipt_recent/SSH

That is all there is to it. You just added an auto blocking rule to your firewall!



Below is the log file parsing PHP-CLI script I mentioned earlier, in case someone is interested.
NOTE: This is a command line PHP script for PHP5. Don't run this through your webserver!

The script will compare the file size since the last run and will only parse it on change. The script will then read the file and find all IPs with too many invalid connection attempts.
This is where it stops since I decided to implement the iptables rules instead of developing this script any further.
You may download the file here: anti_sshd_bruteforce.php
Let me know if you use it for anything useful.

When you run the script it will output an array of IPs which should be blocked. I would process this with a simple foreach loop and generate the iptables rules within. This should work best by creating a separate SSH chain to handle all traffic to port 22 and load the rules after the script execution.
# php anti_sshd_bruteforce.php 
Array
(
[0] => 203.171.30.41
[1] => 119.110.105.8
)

 

No Comments yet .....

 

Add Your Comment:

Note: All posts require administrator approval. Please allow 24 hours for message approval.

Name:
E-Mail:
Title
Plain text only, less then 65 000 characters.

Please write the following string into the box below: UIOPQW

Please answer the question above and type the answer into the text box below.