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.

First:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource

Then run:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 180 --hitcount 4 --name DEFAULT --rsource -j DROP

I’d also recommend using the script in my post on blocking IP addresses using iptables to deal with any persistent folks, or people poking too hard on your web site, or other services.

31 thoughts on “Using IPTables to Prevent SSH Brute Force Attacks

  1. Ahh I guess I figured it out. To make the rules above permanent I just have to save them to a file (as you did in the script in the other article) and edit the interfaces file to load my rules file.

    Thanks a lot! I’m very new to the iptables business and reading through the manual pages I dint really get how to do the 3 attempts thing. So your blog was kind of a live-safer :)

  2. @Andreis: Good question.

    A few answers:

    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.

  3. Thnx this helps me out a lot, I was looking for something like this already.

    @Andries
    Still some clients (like on iphone) don’t support different ports then 22

  4. Pingback: Brute force attack on Twitter - Hack a Day

  5. Pingback: Querystring » Brute force attack on Twitter

    • @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.

        • Good to know. It looks like the deamon mode is new-ish. However it defeats the non-root aspect you mention:

          If you are running DenyHosts in daemon mode then yes you must run DenyHosts as root.

  6. Thanks, great article!
    How would you go about adding these blocks to a separate log file, say /var/log/iptables.log?

  7. Pingback: A secure, standard iptables rule-set for a basic HTTP(s) webserver | DeveloperQuestion.com

  8. Pingback: A secure, standard iptables rule-set for a basic HTTP(s) webserver

  9. 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.

  10. 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).

  11. Thanks for this post.

    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.

  12. 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.

    • The first rule shouldn’t have an Accept. You’ll need to have port 22 opened on your FW already. That rule is to start tracking SSH connections.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>