How to keep your ports private — Port knocking with knockd

Image for post
Image for post
Knock knock, anybody home?

In this article we will be looking at knockd, a port knocking tool, and how we can utilize it on our bastion/firewall server. This guide can be used for a production Linux server or our home Linux-based router. The concepts are the same as well as the purpose.

There are many cogs in the proverbial wheel within the computer security tool kit that all work together to make a more complete security solution for us. Computer security is important for servers and for our home networks.

One of these cogs is to hide things or otherwise make them inaccessible until we want access to it. How can we hide things? I’m glad you asked! Enter knockd, an open source port-knock server that blocks access to a port unless it receives a special “knock” on the door so to speak. This knock is actually a series of connections to specific ports in a specific order. One of the great features is that we can have it only open access to the IP address that we are connecting from!

What is this magic you ask? Well, knockd accomplishes all of this by listening on all the traffic on a machine’s network interface, be it ethernet, ppp, etc., for a sequence of port hits. We can configure knockd to listen for TCP, UDP, or both types of packets. In addition, we can configure the port numbers used in the port knocking sequence, and we can even define how much time is allowed to pass before it stops considering a sequence to be valid.

So you might be thinking “why would anyone want to hide a port?” or “isn’t the point of a server to provide services?” and even “we already have authentication, why do we need to hide the service at all?” These are all valid questions and to answer them it requires us to step back for a moment and remember that sometimes there are vulnerabilities in protocols, services, as well as compromised user accounts. There is also the annoyance of having tons of bots, script kiddies, and the like trying to look for vulnerabilities in our system and spamming our logs with their connection attempts. Anyway, enough of that… let’s move on to installing and configuration of knockd.

We need to install knockd on our server before we can configure and make use of it. In this article I will use Ubuntu in the examples as it is a commonly used operating system, but it should be straightforward to convert the steps to work with a different Linux distribution.

Install the repository package containing knockd:

sudo apt install knockd

The configuration file location is /etc/knockd.conf and using your favorite editor open that file:

sudo vim /etc/knockd.conf

The defaults will look something similar to this:

[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 7000,8000,9000
seq_timeout = 10
tcpflags = syn
command = /usr/sbin/iptables -A INPUT -s %IP% -j ACCEPT
[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 10
tcpflags = syn
command = /usr/sbin/iptables -D INPUT -s %IP% -j ACCEPT

The first section titled “options” controls where the logfile for knockd is stored. This default is fine unless you have a specific requirement.

The remaining two sections are an example of setting up knockd to open and close access to SSH (Secure SHell) as two separate sequences. Let’s go ahead and comment out everything starting with the “openSSH” line by adding pound/hash “#” to the beginning of each line. Alternatively you can delete these lines, but I like to keep them as a quick reference when making edits. Your config should now look like this:

[options]
logfile = /var/log/knockd.log
#[openSSH]
# sequence = 7000,8000,9000
# seq_timeout = 10
# tcpflags = syn
# command = /usr/sbin/iptables -A INPUT -s %IP% -j ACCEPT
#[closeSSH]
# sequence = 9000,8000,7000
# seq_timeout = 10
# tcpflags = syn
# command = /usr/sbin/iptables -D INPUT -s %IP% -j ACCEPT

Now we will want to decide the port knocking sequence we want to utilize. Traditionally the ports used in TCP/IP need to be equal to or greater than 1000 (ports below 1000 are reserved) and less than 65535. For this article’s example, I am going to use 1941, 1942, and 1945. These numbers represent dates when events took place in history. Specifically, 1941 is the year that the code the German Enigma machine used was broken. While 1942 is the year that the Japanese Navy’s cipher (designated JN-25) was broken and finally, 1945 is the year that World War II ended. Yes, I am a history nerd… among other things!

Now we need to decide what port or ports we would like to hide? In my environment I typically hide access to SSH on port 22 and RDP (Remote Desktop Protocol) on port 3389. This scenario applies to both a business as well as a home setup. I need to allow access via SSH for developers and RDP for GUI access for either Windows Terminal Server (multiuser business) or a single user desktop at home. Also, as our society as a whole is generally a forgetful and lazy bunch, it would seem like a good idea to make the ports that are opened to automatically be blocked again after a certain amount of time has elapsed. Note, this will not affect active connections, i.e. you won’t break a running SSH session and only applies to new connection attempts.

Our updated config will now look like this:

[options]
logfile = /var/log/knockd.log
[openSSHandRDP]
sequence = 1941,1942,1945
seq_timeout = 5
start_command = /usr/sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT; /usr/sbin/iptables -I INPUT -s %IP% -p tcp --dport 3389 -j ACCEPT
cmd_timeout = 500
tcpflags = syn
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT; /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 3389 -j ACCEPT

Let’s break down what each line is doing. Under “options” we have our logfile location. Under “openSSHandRDP” we have our knock sequence, followed by the sequence timeout. The sequence timeout is how long in seconds knockd will consider a knock on the ports to be part of one attempt. Next we have our start_command and this is where the opening of the ports happens in the kernel’s firewall. The cmd_timeout is how long in seconds the start_command will be run before we run the stop_command. Which brings us to the stop_command where we delete the two iptables rules from start_command and thereby close the ports back up.

So bringing it all together what we now have is the ability to knock on ports 1941, 1942, and 1945 in that specific order and knockd will do its thing.

Now we need to set a default rule to be in place that denies access to SSH and RDP by default. The place to put this command depends on your firewall. On my bastion I write the firewall rules myself and interact via the iptables command line tool. So on my machine I edit /etc/iptables/rules.v4 which contains two lines that looks like this:

-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j DROP
-A INPUT -i eth0 -p tcp -m tcp --dport 3389 -j DROP

Where “eth0" is the primary network connection. Without this knockd is rather pointless as the ports are always open. If you want to make these changes take affect immediately without a reboot you can simply run “iptables …” where the “…” is each of the lines above:

sudo iptables -A INPUT -i eth0 -p tcp -m tcp --dport 22 -j DROP
sudo iptables -A INPUT -i eth0 -p tcp -m tcp --dport 3389 -j DROP

At this point you should be wondering “this is all fine and dandy, but how do I actually initialization a knock?” This part is easy! We can use a variety of tools: nmap, telnet, knock, and others — basically any utility/command that is capable of opening either a TCP or UDP connection to a given port. The easiest is probably going to be knock since that is its sole purpose.

Let’s get knock installed:

sudo apt install knock

Now we can run it from the command line and send our secret sequence to our remote bastion machine:

knock <hostname/IP> 1941 1942 1945

If you have a slower connection (i.e. tethered cell phone) you can also add the “-d” command line flag to knock. This will add a delay in milliseconds between the knocks on each port. I often use 100 as the option to the “-d” flag. This, in all its glory, would look like:

knock -d 100 <hostname/IP> 1941 1942 1945

We now find ourselves with hidden SSH and RDP services on port 22 and 3389 that will help reduce our attack vector. These ports are only open when we instruct knockd to open them and only open to the IP address we are connecting from. There are many more things you can do with knockd and while in my example I put both 22 and 3389 in the same section (openSSHandRDP), we could have put them into separate sections each with a different port sequence.

I hope this article finds you well and has provided some useful information on what knockd is and how to get started with it. I enjoy receiving feedback; be it suggestions, corrections, or questions. Feel free to drop some love, be safe, and hack away!

I am a SysAdmin, Jr. DBA, and Developer. General interests are in CS, history, vikings, pirates, knights, gadgets, firearms, boating, exploring, and traveling.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store