Block for 20 seconds IP addresses that made more than 3 new connection attempts per 20 seconds:
cat > /etc/iptables/rules.v4 << EOF *filter :INPUT DROP [0:0] :OUTPUT ACCEPT [0:0] :ssh-ban - [0:0] :ssh-check - [0:0] -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ssh-check -A ssh-check -m recent --name SSH --set --mask 255.255.255.255 --rsource -A ssh-check -m recent --name SSH --rcheck --mask 255.255.255.255 --rsource --seconds 20 --hitcount 3 -j ssh-ban -A ssh-check -j ACCEPT -A ssh-ban -j LOG --log-prefix "anti-bruteforce ssh:" --log-level info -A ssh-ban -j DROP EOF iptables-restore /etc/iptables/rules.v4
Disclaimer: Blocking brute-force attempts may not help much if weak passwords are used or if attackers use a large botnet. You should better use ssh keys, or if that is impossible use strong passwords. This is a simple solution, if you want something more advanced, you may use fail2ban.
Since client software usually makes more than one attempt to establish TCP connection, you may noitice that actual ban period is a couple times more than 20 seconds. And let’s see how it works.
- Accept packets for already established connections without further filtering. It is required to not impede established ssh sessions.
- Reject packets that are not starting a new connection or associated with known one. Not necessary, just adds a little more security.
- For a packet initiating a new connection to tcp post 22: redirect to chain
- Add packet’s source address with mask 255.255.255.255 to list named SSH; if it is already there - update existing entry
- If the packet is already in the list and it was seen at least 3 times within 20 seconds:
- Redirect it to the chain
- Redirect it to the chain
- Accept the packet if it was not redirected by the previous rule
- Log the blocked packet attempt to syslog with given message prefix and severity.
- Drop the blocked packet
List of recently seen IP addresses with timestamps for several last packets is available in
/proc/net/xt_recent/SSH. It can be manually altered:
# add addr echo +addr >/proc/net/xt_recent/SSH # remove addr echo -addr >/proc/net/xt_recent/SSH # flush list - remove all entries echo / >/proc/net/xt_recent/SSH
Number of addresses and packets for address remembered per table and other settings may be changed as parameters of kernel module
modinfo xt_recent | grep ^parm parm: ip_list_tot:number of IPs to remember per list (uint) parm: ip_list_hash_size:size of hash table used to look up IPs (uint) parm: ip_list_perms:permissions on /proc/net/xt_recent/* files (uint) parm: ip_list_uid:default owner of /proc/net/xt_recent/* files (uint) parm: ip_list_gid:default owning group of /proc/net/xt_recent/* files (uint) parm: ip_pkt_list_tot:number of packets per IP address to remember (max. 255) (uint)