Stopping brute-force ssh scans the easy way

December 1, 2005

I recently stumbled over this blog entry on a nice, easy way to stop brute force ssh scans, so it's time to spread this knowledge around.

If you've got an ssh daemon exposed to the Internet, you know about the brute force ssh scans and password guessing attacks. The real problem with them is the sheer volume, which creates log clutter (and system load) as they spew login failures and unknown users all over your logs.

(If brute force ssh attacks give you security ulcers, get passwords that follow even basic password security rules, because the scanners pretty much only try obvious simple passwords. Anyone who gets compromised by one should be hideously embarrassed.)

In theory the easy way to stop them is to block ssh access from all the networks that don't need it (even tcpwrappers will do; a few 'connection refused' and the scanners go away). Unfortunately, figuring what such places are (or aren't) can be a slog, and it can change over time, and your users can lynch you when you get it wrong.

Thus the easy way to stop brute force ssh scans is to rate-limit incoming ssh connections; this keeps the log spam down to a couple of entries. Linux iptables can do this using the recent and state match modules, like so:

# iptables -A INPUT -p tcp --dport 22 -s <good-IP> -j ACCEPT

[repeat for all of the netblocks and IPs you want know you want to accept ssh from all the time.]

# 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 60 --hitcount 3 --rttl --name SSH -j DROP

(This blocks people after 3 new ssh connections within 60 seconds. If you prefer different numbers, adjust --seconds and --hitcount to taste.)

Both lines are necessary because you can only give one of --set or --update, and --update does nothing if the source IP address is not already being tracked by the recent module.

You can see the state of this ruleset in /proc/net/ipt_recent/SSH (or whatever name you gave it). Entries can be removed by writing '-IP.AD.DR.ES' into the file, and the entire thing can be purged by writing 'clear'. The ruleset only keeps stuff on the most recent 100 IP addresses, which shouldn't normally be a problem (this is controlled by the kernel module ipt_recent's ip_list_tot module parameter).

Documentation on the recent matcher is here. It is not yet in the iptables manpage, at least in the versions in Fedora Core 4 and Debian Sarge.

Naturally, the kernel side of this has to be built for your kernel, which is yet another reason to always enable NAT et al in your kernel configuration. (I failed to do this on the system where the brute force scanners most annoy me, thereby insuring they will be annoying me for a while more yet.)

(It turns out that I am late to this particular party; people have been talking about this since at least February of 2005.)

Updated December 16th: corrected the iptables usage; my original version had iptables -I instead of iptables -A, with entertaining havoc ensuing.

Written on 01 December 2005.
« An advantage to introspection and an interactive interpreter
Iptables modules that aren't in the iptables manpage »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu Dec 1 03:19:40 2005
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.