DEV Community

loading...

Block SSH brute-force attacks

Florian Engelhardt
Proud dad of five 🧒, husband, Linux 🐧, Vim, PHP 🐘, OpenSource, Geek and I'm getting shit done
Originally published at Medium on ・2 min read

… or at least slow them down (using iptables on Linux)

When having a server with the port 22 open to the internet, you will find a sheer endless number of login tries from various sources. 99% of these are just brute-force or dictionary attacks.

As I do not want my log files to boil over with all these failed logins, I searched for a solution to block them out or at least slow them down.

Here is what I did (thanks @baptistecs for the missing ACCEPT and adding IPv6)

# cleanup
iptables -F
iptables -X SSH_CHECK

ip6tables -F
ip6tables -X SSH_CHECK

# set rules
iptables -N SSH_CHECK
iptables -A SSH_CHECK -m recent --set --name SSH
iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 2 --name SSH -j DROP
iptables -A SSH_CHECK -m recent --update --seconds 3600 --hitcount 10 --name SSH -j DROP
iptables -A SSH_CHECK -p tcp --dport 22 -j ACCEPT # accept packet if not previously dropped

ip6tables -N SSH_CHECK
ip6tables -A SSH_CHECK -m recent --set --name SSH
ip6tables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 2 --name SSH -j DROP
ip6tables -A SSH_CHECK -m recent --update --seconds 3600 --hitcount 10 --name SSH -j DROP
ip6tables -A SSH_CHECK -p tcp --dport 22 -j ACCEPT # accept packet if not previously dropped

iptables -A INPUT -p tcp -s 127.0.0.1 -j ACCEPT # whitelist your IP (replace 127.0.0.1)
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK # jump from INPUT to SSH_CHECK

ip6tables -A INPUT -p tcp -s ::1/128 -j ACCEPT # whitelist your IP (replace ::1/128)
ip6tables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK # jump from INPUT to SSH_CHECK
Enter fullscreen mode Exit fullscreen mode

I am creating a new chain called SSH_CHECK to which i pass on every TCP packet received on port 22 that is in state new (aka syn packet). The source IP address is logged and if the same address occurs two or more times in the last minute or ten or more times in the last hour that packet is dropped.

I also added a rule to bypass the SSH_CHECK chain if the source IP address equals 127.0.0.1 / ::1/128 (replace that with your static IP or just ditch that line).

To be honest, I am not blocking brute-force attacks, but the attacker (or attacking script) can only try one password per minute or nine passwords per hour.

And at last: it is generally a good advice to turn of password authentication in your ssh server as well as root login. Add the following to your /etc/ssh/sshd_config file or change it to read as follows:

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
Enter fullscreen mode Exit fullscreen mode

Discussion (7)

Collapse
baptistecs profile image
Baptiste Clarey Sjöstrand

It would be good to not forget about IPv6 too:

# cleanup
iptables -F
iptables -X SSH_CHECK

ip6tables -F
ip6tables -X SSH_CHECK

# set rules
iptables -N SSH_CHECK
iptables -A SSH_CHECK -m recent --set --name SSH
iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 2 --name SSH -j DROP
iptables -A SSH_CHECK -m recent --update --seconds 3600 --hitcount 10 --name SSH -j DROP
iptables -A SSH_CHECK -p tcp --dport 22 -j ACCEPT # accept packet if not previously dropped

ip6tables -N SSH_CHECK
ip6tables -A SSH_CHECK -m recent --set --name SSH
ip6tables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 2 --name SSH -j DROP
ip6tables -A SSH_CHECK -m recent --update --seconds 3600 --hitcount 10 --name SSH -j DROP
ip6tables -A SSH_CHECK -p tcp --dport 22 -j ACCEPT # accept packet if not previously dropped

iptables -A INPUT -p tcp -s 1.2.3.4 -j ACCEPT # whitelist your IP (replace 1.2.3.4)
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK # jump from INPUT to SSH_CHECK

ip6tables -A INPUT -p tcp -s 1.2.3.4 -j ACCEPT # whitelist your IP (replace 1.2.3.4)
ip6tables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK # jump from INPUT to SSH_CHECK
Collapse
realflowcontrol profile image
Florian Engelhardt Author

Thank you very much, i updated the snippet in the post 👍

Collapse
baptistecs profile image
Baptiste Clarey Sjöstrand

BIG WARNING HERE!

If someone try that and don't add his IP as whitelisted (1.2.3.4 example) SSH connexions won't be blocked but they won't be accepted neither...

It's needed to add this line after the iptables -A SSH_CHECK rules:
iptables -A SSH_CHECK -p tcp --dport 22 -j ACCEPT

Please update the example.

Anyway, thanks for this useful post!

Collapse
realflowcontrol profile image
Florian Engelhardt Author

You are right, this should be made explicit. In my case it was working, as my default for iptables was to accept packages, but i did not state this anywhere in my blog post. I will update the snippet to the one you posted in the other comment.

Good catch and thanks for you valuable input 👍

Collapse
vedraniteh profile image
VedranIteh

Fail2ban jail for creating port 22 (SSH) honeypot

Tired of endless ssh bruteforce attacks ? Even if you are using a certificate or have disabled ssh access completely it will catch a whole lot of compromised IP's and consequently stop some other attack vectors on other ports and services. Port 22 is never missed by a port scan either so you might catch some of these too.

github.com/VedranIteh/fail2ban-ssh...

Collapse
baptistecs profile image
Baptiste Clarey Sjöstrand

Thanks for the update!

FYI, there is the same post on medium which need an update:
medium.com/@dotbox/block-ssh-brute...

Collapse
realflowcontrol profile image
Florian Engelhardt Author

Thanks, i fixed it :-)