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.

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

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>