Anyone who runs their own Linux server knows the annoyance of looking through the log files to see automated SSH brute force attacks trying to find a login to the machine. In the past, I’ve avoided this problem simply by running sshd on a non-traditional port, which makes all the automated scripts that attack port 22 fail.
I recently had to move sshd back to port 22, and I quickly tired of seeing 5k failed login attempts every day.
UPDATE: After some Googling, and after taking into account a lot of good advice from the comments, as well as from John and Smooge, here’s how I’ve rewritten my firewall to protect against brute force ssh attacks.
# set default policies
iptables -P INPUT DROP
# all pre-established clients
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# new inbound ssh, protecting against brute-force attacks
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
The changes improve efficiency by moving all the RELATED and ESTABLISHED filtering to the beginning of the checks. Also, the order of the checks on the NEW ssh connections have been fixed based on the suggestions in the comments.
The blocked IPs are stored in /proc/net/ipt_recent/SSH
.
September 21, 2011 at 12:22 pm
Could also use fail2ban.
September 28, 2011 at 4:42 am
+1.
fail2ban does this quite well for SSH as well as other services.
September 21, 2011 at 1:49 pm
You really saw 5k requests on your box in a day? My machine at home that sits live on a Fiber connection had 477 failed SSH attempts in 3 days!
I used to worry about this, and then I realized that SSHD already implements a connection limit to one per second per connection. At best a malicious user could attempt 86400 times a day, and that’s really not that much.
I think a larger risk is bad passwords. I like your solution though, it’s very elegant.
September 21, 2011 at 3:52 pm
The other thing that I really like is the AllowUsers directive in /etc/ssh/sshd_config
September 21, 2011 at 2:29 pm
denyhosts works too, you even get a nice report a the end of the day.
JAM
September 21, 2011 at 2:50 pm
Max. Could you do an iptables -nxvL of what you said.. the reason is that the order you have printed would say that the 2nd rule might never be gotten to.
September 21, 2011 at 3:26 pm
SMoogen is correct, I’m re-posting the rules with the order fixed and with a small addition to log the attempts:
-A INPUT -p tcp -m tcp –dport 22 -m recent –update –seconds 60 –hitcount 4 –rttl –name SSH -j LOG
-A INPUT -p tcp -m tcp –dport 22 -m recent –update –seconds 60 –hitcount 4 –rttl –name SSH -j DROP
-A INPUT -p tcp -m tcp –dport 22 -m state –state NEW -m recent –set –name SSH -j ACCEPT
-A INPUT -p tcp -m tcp –dport 22 -m state –state ESTABLISHED,RELATED -j ACCEPT
September 21, 2011 at 4:02 pm
Can you explain more about what I had wrong? Thanks!
September 21, 2011 at 8:19 pm
iptables rule processing works on a line by line basis and both ACCEPT and DROP will stop that process and ACCEPT or DROP the connection. In the original order, connections to SSH were accepted on the first line, the rest were not even looked at.
In the new version we first check if the connections to SSH have hit the limit, in which case we LOG (note that LOG does not stop the processing), then we do the same check and in this case we DROP the connection when the limits are hit, or let iptables process the next line because limits are OK. The next line deals with brand new SSH connections, otherwise the next line which deals with existing connections is processed.
September 21, 2011 at 4:50 pm
Best switch to key-based authentication and disable password-based logins altogether. Then you can implement something like monkeysphere to get easy key revocation too:
http://web.monkeysphere.info/
September 21, 2011 at 9:20 pm
Before these rules you may also want to specifically allow ssh traffic from known IP addreses or ranges such as other servers you operate or from the local networks you run.
Good post, good comments.
September 22, 2011 at 4:07 am
My Mom’s PC on AT&T has a modem that uses port 22. I use AllowUsers that only allows one user ID, which itself is 10 characters mixed alpha numeric. I also have /etc/hosts.allow to only accept connections from my ISP which is a very small phone cooperative, 4 counties in rural Wisconsin. There are only 10 hits per day all get dropped before even getting to enter the guess an ID game. If allowed into a guessing game then the hits per day would skyrocket.
September 22, 2011 at 8:20 am
Small clarification, the rule “–rttl” does not track ip address, rather it tracks time to live and is helpful (potentially) if the intruder changes ip addresses (well, it is better then nothing).
See: man iptables
–rttl
This option must be used in conjunction with one of –rcheck or –update. When used, this will narrow the match to only happen when the address is in the list and the TTL of the current packet matches that of the packet which hit the –set rule. This may be useful if you have problems with people faking their source address in order to DoS you via this module by disallowing others access to your site by sending bogus packets to you.
And
http://snowman.net/projects/ipt_recent/
Also note your rules give 4 attempt s minute, I would increase “–seconds 60” to “–seconds 600” , or 10 minutes.
If you use scp or svn over ssh, you will likely need to increase your hit count as each file is a new connection.
September 22, 2011 at 12:07 pm
This technique, known as “connection throttling”, can be applied to any service (web, mail, etc.) you wish to protect against DoS (and might also help in case of DDoS) 😉
September 24, 2011 at 9:50 am
[…] Firewalling SSH brute force attacks. […]
September 25, 2011 at 6:50 pm
Thanks for all the comments. I’ve updated the main post and fixed some of the issues that were pointed out.
September 26, 2011 at 7:27 am
[…] https://spevack.wordpress.com/2011/09/21/firewalling-ssh-brute-force-attacks/ Share this:ShareFacebookEmailPrintDiggReddit […]
September 26, 2011 at 7:59 am
DenyHosts FTW!
September 26, 2011 at 2:55 pm
Or update ssh to use google two phase authentication..
http://www.mnxsolutions.com/security/two-factor-ssh-with-google-authenticator.html
cheers!
September 26, 2011 at 7:14 pm
May not be suitable for individuals . But for companies, try:
taferno.sourceforge.net
Uses Two-factor authentication to alter firewall rules
to allow access to port 22.
September 27, 2011 at 7:48 am
[…] SSH bağlantılarını Brute Force ataklarına karşı firewall korumasına almak […]
October 4, 2011 at 5:49 am
If you only allow specific userids to connect and then don’t use any standard account names (real names like mary or joe) then the risks are very low. If you can’t use the great two – factor ideas outlined above, then only permit ssh key authentication and protect the private keys.
October 4, 2011 at 8:19 am
To get the best of protection, we should implement a holistic approach:
– use throttling via iptables (avoid denials of service and brute force attacks)
– use denyhosts (complements iptables)
– control which users have access to ssh
– make sure root is not allowed to ssh
– use two factor / two phase authentication
– make sure private keys are protected.
– in some cases only allow certain IP addresses