If you’re running a remote server over the internet, you know that it’s crucial to maintain security to prevent unauthorized access. Most remote servers are protected by a firewall that only allows data to pass through specific, numbered ports. However, having open ports may expose your server to potential risks as attackers can easily spot them and try to gain unlawful access.
That’s where port knocking comes into play - it’s a technique that enables you to keep your ports closed while still allowing authorized users to connect to your server. In this article, we’ll delve deep into the concept of port knocking, how it works, and how to implement it using Knockd, a Linux-based port-knocking utility.
In general, when you want to connect to a remote server, you send some data over the network to an IP address of the server, specifically to a numbered port at that IP address. The open ports on the server’s network are then exposed to the internet.
With port knocking, you can configure your server to have no open ports at all. Instead, it will only open a port for a brief period when there is a specific sequence of connection requests sent to it. This makes it challenging for an attacker to identify the open ports and gain access to your system.
To get started with implementing port knocking, we will need to use Knockd, a lightweight port-knocking utility. Knockd is widely used in the Linux community and is easy to configure.
Firstly, we need to configure Knockd by specifying the sequence of connection requests that it needs to listen for.
Here is an example of a configuration file with two sequences that will open port
8888 if Knockd sees a sequence of requests on port
8000, and then
9000, all within five seconds. The second rule does the opposite, closing port
8888 if it receives the opposite sequence.
[options] logfile = /var/log/knockd.log [openSSH] sequence = 7000,8000,9000 seq_timeout = 5 tcpflags = syn command = /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT tcpport = 22 [closeSSH] sequence = 9000,8000,7000 seq_timeout = 5 tcpflags = syn command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpport = 22
As you can see from the file, the rules listen for a specific sequence of connection requests, then use IPtables to add or remove rules to open or close the specified port.
Now that we understand how Knockd works, let’s see how we can implement it in a real-world scenario. We’ll then use Knockd to configure port knocking so that the port is only open when we send a specific sequence of connection requests.
Create a new directory where you want to store your files. Then, create a file called
Dockerfile will following content
FROM python:3.8-alpine RUN apk add --no-cache \ iptables \ knock COPY ./entrypoint.sh ./ RUN chmod +x ./entrypoint.sh COPY knockd.conf /etc/knockd.conf COPY ./index.html ./ CMD [ "./entrypoint.sh" ]
The Dockerfile installs Knockd and IPtables, then copies in our configuration files and starts everything up using an entrypoint script.
Next, create a simple
Makefile with the following content
build: docker build -t port-knock-demo . run: docker run -d \ --rm --privileged \ -p 8000:8000 \ -p 7000:7000 \ -p 9000:9000 \ -p 8888:8888 \ --name port-knock-demo \ port-knock-demo unlock: -telnet 127.0.0.1 7000 -telnet 127.0.0.1 8000 -telnet 127.0.0.1 9000 lock: -telnet 127.0.0.1 9000 -telnet 127.0.0.1 8000 -telnet 127.0.0.1 7000 test: curl -m 1 127.0.0.1:8888 view-logs: docker exec port-knock-demo cat /var/log/knockd.log
Next, create a file called
entrypoint.sh with the following content
#!/bin/sh # NOTE: Docker opens up port 8888 because I am port forwarding # to it in my docker run command so I have to reclose it here /sbin/iptables -A INPUT -p tcp --dport 8888 -j DROP & \ knockd & \ python -m http.server 8888
The contents of
knockd.conf are the same as the example above.
Finally, create a file called
index.html with the following content
<!DOCTYPE html> <html> <head> <title>Port Knocking Demo</title> </head> <body> <h1>Port Knocking Demo</h1> <p>This is a demo of port knocking.</p> </body> </html>
Now you can build and run the Docker container using the following commands.
make build make run
Once the container is up, we can test our port knocking process by attempting to connect to our Python server on port
However, since that port is closed currently, it won’t work. We then fire off a sequence of telnet requests on port
Now, we can test the connection again and it should work.
To re-lock the port, we just send those same telnet requests in the reverse order,
Now, the server will no longer listen to the port and our request will timeout.
Port knocking is a simple yet effective way to enhance network security by closing your server’s ports until it receives a specific sequence of connection requests. It can be implemented quickly and easily using Knockd, which is lightweight and easy to configure.
By following the steps above, you should be able to implement port knocking on your own systems with ease. However, it’s good to remember that port knocking should be viewed as one component of broader network security strategy rather than the sole solution.