Using IPTables to Prevent SSH Brute Force Attacks

If you have a server with a world facing ssh server, you’ve probably seen brute force attacks in your logs. Some machine starts hammering your ssh server, trying all sorts of logins (staff, root, a, admin, etc…) over and over and over again.

This is bad on a lot of fronts.

I use two simple iptables rules to block any IP address who has made more than 3 ssh connections or attempted connections within the past 3 minutes. So your would-be brute force attacker, gets three tries, and then is locked out for a minimum of three minutes. However, since 99% of the attacks are run by an automated bot, it will either: give up after the connection is refused multiple times, or it will keep hammering away on the closed door, which keeps the running count of attempted connections in the past 3 minutes over 3, keeping the door closed.

As for the block, it’s just for a few minutes (in case I lock myself out – which I’ve done before), but totally breaks any brute-force attempt, since they never stop trying, and hence stay blocked out until they’ve given up.

1) a different port is a good idea for part of a security solution, but you should still have measures in place to prevent brute force attacks. Port scanning to identify ssh server ports isn’t hard. You might duck a large number of automated scanners, but it won’t do anything for a targeted attack. My solution will. So you should do the above anyhow:)

2) one of the main reasons I don’t run on a different port myself is convenience. I ssh in from a large number of other servers, and scp files frequently. Having to specify a port every time I do any of that would be a pain.

[…] Wired Threat Level has posted an interview with the hacker who recently broke into several high profile twitter accounts, such as Fox News, and Barack Obama. Since we know how much you all love twitter, we thought you might want to learn more about it. Apparently he used a brute force method to get into a member of the support team. The password was “happiness” which was cracked pretty quickly. This might be a good time to review your own strategies to prevent brute force attacks. […]

[…] Wired Threat Level has posted an interview with the hacker who recently broke into several high profile twitter accounts, such as Fox News, and Barack Obama. Since we know how much you all love twitter, we thought you might want to learn more about it. Apparently he used a brute force method to get into a member of the support team. The password was “happiness” which was cracked pretty quickly. This might be a good time to review your own strategies to prevent brute force attacks. […]

@James: Yes, it’s a similar approach. However there are a few reasons you might want to consider using the iptables rules instead of the denyhosts service:

DenyHosts runs periodically (either via cron or as a deamon), and in the FAQ the author recommends running it every 10 minutes. Your server will take a very high number of brute force attempts in 10 minutes. The iptables rule will block after 4 attempts, much more quickly than denyhosts, and hence reduces the chances of a successful brute forcing attempt.

I don’t like running processes as root, like DenyHosts. The only real advantage of DenyHosts is the new synchronization mode, which would let you block servers that haven’t even attacked you yet, saving your the four attempts the iptables rule would allow. However, running a python script as root, that pulls data from a 3rd party non-SSL server and then uses that data to modify my server’s hosts.deny file. Doubly so when that data is already being collected from other users of this 3rd party service. I’m not sure what prevents a malicious user of the service from submitting perfectly legit IPs or IP ranges and having the synchronization service push that data out to all the other users. I.e. I could submit all Comcast IPs and have them get blocked by users of the service, even though they are legit. Also, with the lack of SSL, I’d worry about the possibility of cache poisoning or DNS poisoning attacks being another vector to poison the data going into the hosts.deny file.

The hosts.deny file is used for ALL services, not just SSH. This would prevent people with infected PCs from visiting your websites.

The hosts.deny file is only read by tcpwrappers, and not all programs use it, so if I really did want to block all services, it might not suffice.

Mostly it comes down to me liking the control that iptables gives me, and being somewhat paranoid:)

Denyhosts can be run in daemon mode which will actively monitor ssh logins and update hosts.deny immediately. Further it is possible to run the daemon as a non-root user (see http://denyhosts.sourceforge.net/faq.html#3_1). And lastly it is possible to tell denyhosts to block only a specified service instead of all services. Personally, I would rather block all communication from a compromised host.

Thanks for this. I didn’t even realize I had a problem until my /var volume filled up due to a tremendously large /var/log/btmp file. Combining this with blocking a few frequent ip addresses, and the problem seems to be under control.

Question:
So, say I’m having a bad day, and can’t remember my password. I try it five times in one minute, all failing to be correct. Am I locked out from whatever IP I’m at until I remove myself from the IPTables block list, or will it let me in if I get it correct after waiting a couple minutes?

Okay, cool, thanks! I just tried it, though, and it never locks me out to start with. I intentionally put in a wrong password five times in a row (all within about a minute), and it let me in on try number six (even though I didn’t wait at all for it).

I was trying to find a way to view the ips that are currently in the block list, however there doesn’t seem to be an iptables command that I could find. The ‘DEFAULT’ list referenced in the rules seems to be located here though: /proc/net/xt_recent/DEFAULT; I’m not sure if you know of a better way?

You can set up another chain and let it do LOG and DROP. The log entries are in syslog and dmesg. If you have a smart logger (Debian can use rsyslog), you can specify those entries to go into their own file such as iptables.log.

Google for “iptables ssh log”, there are plenty of examples. They follow the same principle as here with a bit extra for the logging.

I cannot get this to work – with just these two rules (the first of which does not specify ACCEPT), I cannot connect over SSH at all. If I add the ACCEPT target to the first rule, I can still bomb my server over and over and the DROP rule never comes into effect.