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.