Managed Kubernetes now available in Open Beta. Test out the new service yourself at your Control Panel.
Managed Kubernetes now available in Open Beta. Test out the new service yourself at your Control Panel.
In this article are shown example instructions for a simple firewall disallowing new connections if the remote host initiates a connection too often. This is especially the case with SSH brute force attacks. Most administrators know the feeling of annoyance when they look at the system security logs and notice the enormous amounts of failed SSH logins.
What makes the described solution effortless is that there is no need to install and configure a separate log watcher daemon – just bring in some firewall rules. The setup might be most useful in the context of security-sensitive hosts where additional security measures would be justified, even more so if, for some reason, strong (e.g. key based) authentication can’t be used.
This article describes deploying IPv4 address bans based on how often a remote client tries to connect to a specific port, using netfilter‘s iptables and ipset tools.
Matching lists of addresses or networks by using just iptables is indeed messy because iptables as itself does not support matching multiple separate addresses or networks in one rule. This means that every checked address or network would need their own rule in the ruleset. Such complicated and long rulesets bring administration and performance concerns.
With ipset a list of addresses (or networks, etc.) can be matched from one rule. Performance considerations such as indexing the address set make matching and lookups a lot more efficient.
The example is as on CentOS 7. Similar should be achievable on other systems too.
First, the needed tools should be installed:
yum install iptables iptables-services ipset ipset-service
All offending IPv4 addresses are going to be saved, open the following file for edit:
vi /etc/sysconfig/ipset-config
And set IPSET_SAVE_ON_STOP="yes".
The ipset in this example is created with the timeout parameter which makes the set’s entries expire. Without the timeout, the entries will last until removed by hand.
ipset create sshin_bans hash:ip timeout 3600 service ipset save systemctl start ipset systemctl enable ipset
Insert desired ruleset into /etc/sysconfig/iptables. Following is a simple example ruleset:
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :SSHIN - [0:0] # 1 -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -s 10.0.0.0/12 -m conntrack --ctstate NEW -j ACCEPT # 2 -A INPUT -m set --match-set sshin_bans src -j DROP # 3-4 -A INPUT -p icmp -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j SSHIN # 5 Block direct SSH bruteforce -A SSHIN -m recent --set --name bruteforce -A SSHIN -m recent --update --seconds 3600 --hitcount 5 --name bruteforce -j LOG --log-level info --log-prefix "SSH blocked: " -A SSHIN -m recent --update --seconds 3600 --hitcount 5 --name bruteforce -j SET --add-set sshin_bans src -A SSHIN -m recent --update --seconds 3600 --hitcount 5 --name bruteforce -j DROP -A SSHIN -j ACCEPT # 6 if you want to filter ports: #-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT #-A INPUT -j REJECT --reject-with icmp-host-prohibited #-A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT
Explanation of the above ruleset:
Then enabling the ruleset:
systemctl start iptables iptables-restore /etc/sysconfig/iptables service iptables save systemctl enable iptables
In this setup, the ban list is persistent as the set is saved upon shutdown but the bans expire after 1 hour. Blocked addresses can be delisted manually by using the following command:
ipset del sshin_bans 172.16.6.10
This removes an address from the set and allows that host to connect again, provided it does not trigger a new ban from iptables‘s recent match.
With ipset and the SET target it’s easy to catch also those hosts which try to connect to a port with no daemon listening on it. If there supposedly was nothing listening on port 25, just by having a rule such as -A INPUT -p tcp --dport 25 -j SET --add-set honeypot_victims src adds the remote host to the honeypot_victims set when the offending host matches the chain – i.e. the remote host tried to connect to port 25.
To enable this honeypot, add the rule to your /etc/sysconfig/iptables file.
-A INPUT -p tcp --dport 25 -j SET --add-set honeypot_victims src
Then create the honeypot_victims jail using ipset, save the config and restart the software.
ipset create honeypot_victims hash:ip timeout 3600 service ipset save systemctl restart ipset systemctl restart iptables
It should be clear anyway that one got to know what they are doing when using this kind of setup. There might be innocent errors that make clients connect to the wrong host or port and denying access on the basis of so primitive heuristic might open up the chance for denial of service.
The access control method shown in this article is lighter and more streamlined because it does not need a separate log watcher daemon (e.g. fail2ban). Another good thing is that Netfilter is usually readily available and in use anyway, so accommodating a few more rules to the ruleset does not require much extra effort.
This is not, however, a universal solution. The real downside is that Netfilter counts only incoming connections, not failed logins, and therefore it could be more easy to accidentally lock oneself out or accidentally cause a small denial of service.
Still, the principal solution for denying access to abusive hosts as described in this article has been tried and tested by the author for a considerable length of time. Even on a small-scale multiuser system, there has only been a tiny amount of bans for legitimate users over several years (one or two cases) but obviously, this is not a large-scale multiuser solution.
If the presented example solution wasn’t suitable, a better and more intelligent solution might be sshguard which has the ability to catch offenders during a longer timespan. sshguard can feed IP addresses into an ipset set too.
BruceW
This is was the best tutorial I found on ipset. Thank you!
I was able to adapt this to a linux-based SIP phone system very easily.
Mark
Thanks so much for this tutorial, it’s super useful!
alex
Hi great info thank you, However, I have installed ipset on ubuntu 20.x using “sudo apt install ipset” there was no “ipset-service” package for ubuntu and thus no /etc/sysconfig/ipset-config and no /etc/ipsec.d/*.conf
So I can not issue any of the followings!!
service ipset save
systemctl start ipset
systemctl enable ipset
Any ideas?
alex
Thank you, you have been a great help, I have a pretty beefy Ubuntu server and I have 119K DENY/24 rules in my UFW and I need to do something better and I think ipset is a better choice, I am going to create a 64K ipset set lists (using php scripts) and load them in via bash and then reference each list in my iptables one after another, is that a workable solution?
If my testing proves all is OK, I am going to uninstall UFW and just work directly in iptables/ipset.
Thanks
alex
Hi, I am trying to play with the honey potting and have couple of questions
1) Is this syntax correct in above article? “-A INPUT -p tcp –dport 25 -j SET –add-set honeypot_victims src” specifically the “-j SET”?
2) The man pages show that the –add-set is here from iptables 1.8.3, but my v1.8.4 throws this error –> iptables v1.8.4 (legacy): unknown option “–add-set” when I try your example for honeypot above!! my ipset is “ipset v7.5, protocol version: 7”
I can’t find clear explanation of “-m set” so I tried this syntax which also errored with above iptables errors.
“sudo iptables -A INPUT -p tcp –dport 25 -m set –add-set honeypot_trap src -j DROP”
I tried the this syntax so I can store the src address and drop the packet.
Please advise.
thanks
Alex Atari
on the above post the double dashes for ‘add’ and ‘dport’ somehow getting changed to a single dash in this portal, just wanted to mention that the syntax of the keywords were correct and have double dashes when getting issued in my Linux.
Andy
We can block brute force attack by using recent module only (without ipset):
-A INPUPT -p tcp -m tcp –dport 22 -m conntrack –ctstate NEW -m recent –set –name bruteforce –mask 255.255.255.255 –rsource
-A INPUPT -p tcp -m tcp –dport 22 -m conntrack –ctstate NEW -m recent –update –seconds 60 –hitcount 3 –name bruteforce –mask 255.255.255.255 –rsource -j DROP
Is there any advantage of using “recent + ipset” over “recent” only ? Is ipset more efficient than recent module when thousands of ip addresses are blocked ?
shane
Hi Andy, could you share the rule for blocking brute force for the most recent version of IPtables please?
Janne Ruostemaa
Hi Shane, thanks for the question. The same rules as used in the tutorial should still work in the latest version of iptables.