Mitigating against SSH brute force attacks using Netfilter and the recent module
As I mentioned previously, I recently discovered the wonders of Netfilter's recent module, and have decided to try and employ it to ward off the evil script kiddies and their brute force SSH scripts.
As I like to be able to SSH to my server from where ever I happen to be, and I won't necessarily have the infrastructure to use public key based authentication, I thought I'd see how a bit of selective packet filtering would go.
I'm using:
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH -j ACCEPT iptables -A INPUT -p tcp --dport 22 -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j LOG --log-prefix "SSH_brute_force " iptables -A INPUT -p tcp --dport 22 -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP
This will allow three port 22 connections from any given IP address within a 60 second period, and require 60 seconds of no subsequent connection attempts before it will resume allowing connections again. The --rttl option also takes into account the TTL of the datagram when matching packets, so as to endeavour to mitigate against spoofed source addresses.
As an additional nicety, I could refine this to use a custom chain and a whitelist that exited the chain for source IPs that were trusted.
I'm going to run this ruleset on my server for a while and see if I
- don't lock myself out
- make a dent in SSH brute force attacks
Update
After much discussion with Juergen Kreileder, this ruleset would appear to be slightly better:
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 -j SSH_WHITELIST iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j ULOG --ulog-prefix SSH_brute_force iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP
This has the (arguably) added benefit of not hosing any established SSH connections from the host that has made too many SSH connections in a short period of time, and allows for whitelisting.
Update
I've had a few people email me and ask about the whitelisting part, which I didn't do a terribly good job of explaining. I should have said that you need to create a custom chain first:
iptables -N SSH_WHITELIST
and then add whitelisted hosts to it in a manner like this:
iptables -A SSH_WHITELIST -s $TRUSTED_HOST -m recent --remove --name SSH -j ACCEPT
this clears the whitelisted host out of the recently seen table, and because is has an ACCEPT jump target, should stop further processing anyway.