SSH Dictionary Attack Prevention with iptables

Tagged in

Last week (9-15 April). 8,750 failed SSH login attempt, averaging almost one per minute, trying out all kinds of possible user names and left tons of junk in my message log. The recent SSH brute-force attacks (actually it’s not that recent) are rather annoying, and this article at Whitedust.com has useful information on how to prevent this kind of attacks.

For me I have always used AllowUsers directive in /etc/ssh/sshd_config to limit the users that can login. In my setup, I have

AllowUsers root@home-IP my-regular-login

It allows root ssh login, but only from my home ADSL connection with static IP address so I can automate backups. Then it also includes a user ID that I regularly use to log into this VPS. If I need to do some system administration, I’ll use either su or sudo once I am inside.

However I found it is also ideal to slow down the attack when the infested host started to brute force the SSH authentication. There are many scripts/user-land daemons that perform monitoring and blocking. However in a resource limited VPS, I prefer to use something that has less demand in memory/CPU usage. IPTables recent module provides a kernel level solution with little overhead.

This is what I have in my iptables rules:

iptables -N SSH_CHECK
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK
iptables -A SSH_CHECK -m recent --set --name SSH
iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

What it does is:

  1. Create a new chain SSH_CHECK, and all incoming SSH connection (TCP port 22) will go into this chain to test the condition.
  2. Condition is, for any source IP address there cannot be more than 3 SSH connection attempts within a 60 seconds window.
  3. If condition has been met, then all packets from that source IP address will be dropped.
  4. That source IP can only connect again if condition is cleared again, i.e. there has been 60 seconds of quiet time.

I found it quite effectively and dramatically reduce bot attacks on SSH port. Still, it is important to remove shell access from users that no longer require it, and choose sensible random password that is difficult to guess.

Comments

This is pretty cool, and I tried it with iptables 1.3.5 on a recent install of Fedora 5 and it worked as advertised. Unfortunately, it doesn’t work with iptables 1.3.0, which is what is running on my production boxes. When I tried to upgrade to 1.3.5 I got this:

error: Failed dependencies: libc.so.6(GLIBC2.4) is needed by iptables-1.3.5-1.2.1.i386 rtld(GNUHASH) is needed by iptables-1.3.5-1.2.1.i386

And when I tried to install that, I got:

rpm —test —install glibc-2.4.90-17.i386.rpm

warning: glibc-2.4.90-17.i386.rpm: Header V3 DSA signature: NOKEY, key ID 30c9ecf8 error: Failed dependencies: glibc-common = 2.4.90-17 is needed by glibc-2.4.90-17.i386 glibc > 2.3.5 conflicts with glibc-common-2.3.5-10.3.i386

Which looks like a quagmire I’d rather not step in.

Gravatar

Well. RPM hell. That’s why I have been running Gentoo for the last 3 years.

Alternatively you can use the source RPM. You might need to look up RPM manual to work out how to build source RPM, but basically you’ll be able to install a later version of iptables without all those dependency issues, provided the source can be compiled cleanly in your current configuration.

Gravatar

I love this iptables rule … the ssh haven’t really bothered me until some recent punks were hitting my box very quickly and causing bandwidth problems.

Is there a way to modify this rule so we can ban them longer? It seems the 60 second rule applies to the 60 second window as well as the ban time.

Mark

Gravatar

NB: You need a rule AFTER this to allow ssh connections that have gotten through, assuming that is that the last rule in your ruleset is a drop.

I also had to remove the existing ‘allow port 22’ rule that appeared BEFORE this!

I have:

iptables -P INPUT ACCEPT iptables -F iptables -X iptables -A INPUT -p tcp -m multiport —destination-ports 25,80,110,143,443 -j ACCEPT iptables -A INPUT -p icmp -j ACCEPT iptables -A INPUT -p tcp -m state —state ESTABLISHED -j ACCEPT iptables -A INPUT -p udp -m state —state ESTABLISHED -j ACCEPT

prevent dictionary attack

from http://hostingfu.com/article/ssh-dictionary-attack-prevention-with-iptables

iptables -N SSHCHECK iptables -A INPUT -p tcp —dport 22 -m state —state NEW -j SSHCHECK iptables -A SSHCHECK -m recent —set —name SSH iptables -A SSHCHECK -m recent —update —seconds 60 —hitcount 4 —name SSH -j DROP iptables -A INPUT -p tcp -m multiport —destination-ports 22 -j ACCEPT

iptables -A INPUT -j DROP

Gravatar

Hi,

I have a Fedora 4 box that I use as my development server. I tried the above ruleset and it did not work. I am really tired trying out various such iptable recent module rules from different sites/tutorials etc. to prevent brute force attacks, none seems to work for me, not sure why. It must be my mistake, but I am not able to figure it out. Sometimes, it seems like the rules work, but after 3-4 days I again get thousands of failure attempts in my log files.

Here is what I have on my iptables file:

:SSH_CHECK - [0:0]
-A INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -j SSH_CHECK
-A SSH_CHECK -m recent --set --name SSH --rsource
-A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j DROP

The eth1 is my external interface that is on a public IP address. The —rsource option automatically gets inserted when I do a iptables-save > iptables, I do not type it.

What I do is, edit my iptables file, put the rulset and then restore by iptables-restore < iptables, restart iptables service by service iptables restart, and then save it by iptables-save > iptables. When I save, the —rsource automatically gets added to the rules.

Can anyone help me setting up a correct rule set? My knowledge level is low and I will probably not understand if your answer is short, please forgive my ignorance.

Thanks in advance.

Gravatar

DK,

What I found is,

  • These rules are only limiting new connections from the same IP to up to 3 per minute. Therefore you will still see a lot of failed login attempts, but they are throttled.
  • 3 per minute is on also calculated from source IP. Therefore you can still get lots of failed attempts from different source IP.

At the end, if you definitely know where you will be logged in from, it might be better to use iptables rules to limit only these IP addresses/networks. Using “recent” module will only reduce the rate, but will never eliminate the attacks.

Gravatar

Unfortunately I see 30-40 attempts from the same IP address in the same minute. That’s why I say this ruleset is not working. I have iptables 1.3.0 running on my fedora 4 box. Is this the cause?

Gravatar

I find it easier to turn off challenge (keyboard interactive) authentication and exclusively use keys to authenticate. Then I also change the port from 22. On one box I have it on 443 (allows me to poke a hole in most proxy’d networks - then I can jump to whatever box & use my own http proxy & socks proxy) and the others on a random high port.

No more mess in my logs :D

I then have my keys stored in a TrueCrypt volume on my USB thumb drive. This truecrypt volume is copied to my pc & gmail accounts. Also have portable putty & winscp in there too, very helpful :)

Gravatar

It works really good. I tried it in SuSe 10.2. You have to use hooks in /etc/sysconfig/scripts/SuSEfirewall2-custom according to the description and modify options 25, 31 in /etc/sysconfig/SuSEfirewall2, that is

FW_CUSTOMRULES="/etc/sysconfig/scripts/SuSEfirewall2-custom"
FW_USE_IPTABLES_BATCH="no"

So you can get this IP-chain at the “right position” in the SuSe-Firewall integrated. I have tested it myself from the remote desktop, even though i don’t really need this nice feature (i use only public key identification) it helps to keep your log-files clean.

Gravatar

Where/how to find the list of current banned IP addresses when using iptables?

I mean the current IP addresses that are dropped because of rule:

iptables -A SSH_CHECK -m recent —update —seconds 60 —hitcount 4 —name SSH -j DROP

Gravatar

Banned IP address are found under:

/proc/net/ipt_recent/

To delete an IP address from the file:

echo ‘-[ipaddress]’ >[bannedipfile]

Post new comment

The content of this field is kept private and will not be shown publicly.

More information about formatting options