Posted by Zack Hamm on November 13, 2020
Nerd Title: Security Ubuntu Server with tcpwrappers and ufw.
We don’t write many cybersecurity related articles because there are plenty of other people out there also doing it, and well… we can’t be experts at everything.
Still, once in a while we come up with a problem that has a solution so clean and elegant that we have to share it. This article will quickly explain how to setup tcpwrappers and a firewall to automatically ban users attempting to connect from unauthorized IP addresses. The process is simple, every modern linux distribution comes with a firewall of some kind, Ubuntu currently uses ufw. It also supports a package called ‘tcpd’, or tcpwrappers. The solution we used was to install a base ufw rule limiting only ports for SSH, HTTP, and HTTPS traffic and block everything else. It looks something like this:
email@example.com:/root/# ufw status
To Action From
-- ------ ----
22/tcp LIMIT Anywhere
443/tcp ALLOW Anywhere
80/tcp ALLOW Anywhere
22/tcp (v6) LIMIT Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
This is a common configuration, but the downside is that everybody can knock on your door and attempt to login. You can limit how much/how fast, but basically it’s open to the public. This is where tcpwrappers comes in. You can search the internet about tcpwrappers, there are many online explanations and guides about it. Tcpwrappers has been around a long time, and they never changed the goofy name, but essentially it works by checking two files: /etc/hosts.allow and /etc/hosts.deny to see if you’re a good guy or a bad guy, and what to do with you. This is where the fun comes in. (Note, you’ll need root permissions to do this.)
First you have to install tcpwrappers – “sudo apt install tcpd”
Then edit the /etc/hosts.allow file and add the services you would use, something like this (change your own hostnames or IP addresses you want to allow in):
ALL: 188.8.131.52 # Work Server
ALL: 184.108.40.206 # Home
ALL: rockhouse.mynetgear.com # Home
ALL: 220.127.116.11 # Testing Cloud Server
The IP addresses or hostnames with ALL: in front are allowed into the server for whatever port or service they connect to, as long as the firewall rule allows it. This is your “whitelist” of good guys to let in the door. The big difference here is that unlike firewall rules, tcpwrappers allows for hostnames, so if you have a dynamic IP address using a hostname (like dyndns.org), you don’t have to update the firewall rules each time. Need to add a new remote host that should be allowed to access ssh? Add it here.
Next, edit the /etc/hosts.deny file and add the following string (it should all be on one line):
ALL: ALL: spawn ((/usr/local/bin/banip.sh %h; /bin/echo -ne "client = %h; server = %H; process = %d; PID = %p date = "; /bin/date) >> /var/log/tcpwrappers.log &)
This single line blocks everybody from everything that isn’t in the whitelist above. Notice also here tcpwrappers calls a shell script called /usr/local/bin/banip.sh. This script calls “ufw” to write a firewall rule to ban the remote attacker forever. You can put this wherever you want, but the script should look something like this:
#This script attempts to ban ip addresses using Ubunutu's UFW
if [ `whoami` != "root" ]; then
echo "you must be root to run $ME"
if [ "$1" = "" ];
echo -n "Enter the IP Address: "
echo -n "You entered $IP, correct? (Y/N) "
if [ "$ans" = "y" -o "$ans" = "Y" ]; then
echo "Blocking $IP"
ufw insert 1 deny from $IP port 22
echo "Ok, quitting."
echo "Blocking $1"
ufw insert 1 deny from $1 port 22
This is a very simple script that takes an IP address and tries to ban it on port 22 for access using ufw. If you run it manually without any arguments it will ask you for an IP address to ban.
This script will also create a logfile in /var/log/tcpwrappers.log that you can see where people have tried to gain access to your server and been shut out.
Skipping adding existing rule
client = 18.104.22.168; server = 22.214.171.124; process = sshd; PID = 78110 date = Fri 13 Nov 2020 04:54:48 AM UTC
client = 84-255-249-179.static.t-2.net; server = 126.96.36.199; process = sshd; PID = 78153 date = Fri 13 Nov 2020 04:55:19 AM UTC
client = ns3268691.ip-5-39-81.eu; server = 188.8.131.52; process = sshd; PID = 78167 date = Fri 13 Nov 2020 04:55:36 AM UTC
You can also see a list of banned IP addresses by typing “ufw status”. If you’ve accidentally banned an IP you didn’t mean to, then you can unban it by using “ufw delete rule#”, where rule# is the actual line from “ufw status numbered” that you want to unban. Note that this list can get rather long, as there are people with nothing better to do than write scripts to try to break into whatever servers they can find. In the short time I wrote up this article, I had 32 attempts on my demo server alone. If you need to reset, you can just type “ufw reset”, but that resets everything back to factory defaults. You can use a quick script to do this also:
sudo ufw --force disable \
&& sudo ufw --force reset \
&& sudo ufw default deny incoming \
&& sudo ufw default allow outgoing \
&& sudo ufw allow 22/tcp \
&& sudo ufw limit ssh \
&& sudo ufw allow 80/tcp \
&& sudo ufw allow 443/tcp \
&& sudo ufw --force enable
This has been a very fundamental explanation of how to easily allow remote access while also keeping the bad guys out at the same time, using a blend of the old (tcpwrappers was written in the 1990’s) and the new.