disflux blog UNIX and other musings

19Mar/110

Blocking SSH Brute Force attempts with OpenBSD’s pf

As anyone with a public facing IP address knows, you will eventually see massive amounts of bruteforce attempts on your SSH port by script kiddies attempting to gain access:

...
Mar 15 12:02:34 prime sshd[6518]: Invalid user nagios from 50.23.135.86
Mar 15 12:02:35 prime sshd[6520]: Invalid user nagios from 50.23.135.86
Mar 15 12:02:36 prime sshd[6522]: Invalid user weblogic from 50.23.135.86
Mar 15 12:02:37 prime sshd[6524]: Invalid user weblogic from 50.23.135.86
Mar 15 12:02:38 prime sshd[6526]: Invalid user weblogic from 50.23.135.86
Mar 15 12:02:39 prime sshd[6528]: Invalid user ftp1 from 50.23.135.86
Mar 15 12:02:39 prime sshd[6530]: Invalid user ftp1 from 50.23.135.86
Mar 15 12:02:40 prime sshd[6532]: Invalid user ftp1 from 50.23.135.86
...

While there are several methods for blocking these attempts, such as denyhosts, I was looking for a simpler solution. I am already running OpenBSD's pf on my FreeBSD VPS, so a solution using pf seemed like the way to go. While FreeBSD has a handbook entry on how to accomplish this, I found a site that explains how to do this with two simple rules.

The first rule, which should be early in your rules configuration will block all inbound traffic from hosts that are in the ssh-bruteforce table:

block drop in quick on $ext_if from <ssh-bruteforce>

The rule says "block all packets from any hosts in the ssh-bruteforce table without processing any more filter rules." This rule is useless without anything in the ssh-bruteforce table, so the next rule is where the magic happens:

pass in on $ext_if proto tcp from any to ($ext_if) port ssh \
flags S/SA keep state \
(max-src-conn-rate 3/30, overload flush global)

This rule uses pf's max-src-conn-rate to start populating the ssh-bruteforce table. This rule tells pf to allow inbound connections on port 22 but if any host tries to connect more than 3 times in 30 seconds, add that host to the ssh-bruteforce table, effectively blocking that host from connecting at all. Examining the table after a few hours or days, we see:

prime# pfctl -t ssh-bruteforce -T show
24.222.76.98
58.68.231.29
60.191.121.170
61.180.240.17
88.191.63.71
...

This table can fill up fast if you have a lot of bruteforce attempts, so a cron script to flush that table at times may be necessary.

Of course you can tune your rule for different time lengths and number of connections, but be careful not to lock yourself out by setting the values too low. To an attacker it appears as if your server disappeared and they will move on to the next target and leave you alone. I think this is a clean, elegant solution, and works well.

Filed under: security, ssh, unix Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

(required)

No trackbacks yet.