How to Obscure Network Ports with a Port Knocking Sequence on Debian 10
Port knocking is a method of dynamically opening network ports by "knocking" (i.e. connecting) on a predefined sequence of ports. This is especially useful for obscuring an open network port from port scanning since the port in question will be closed unless the port knocking sequence is executed. A long enough port knocking sequence is practically impossible to brute force: for example, to successfully guess (by brute force) a combination of 3 TCP ports, an attacker would have to try knocking on each of the 281 trillion possible combinations, and scan for open ports after each port knocking sequence. As you can probably imagine, this would take a very, very long time.
This guide will help you through the installation of knockd, a flexible port knocking daemon, on Debian 10. For demonstration purposes, we will configure it to obscure the SSH port, though any other port/service can be protected with this approach.
Requirements
- A server running Debian 10.
- Root access to your server.
- The $EDITOR environment variable should be set.
- A second system for testing.
NOTE: If you intend on using port knocking to obscure the SSH port, make sure you have an alternative access method (via console for example), which will come in handy if you accidentally lock yourself out.
Before installing knockd, check the name of your system's public network interface with the following command:
ip link show | grep -v lo
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
Take note of the interface name (ens18 in this case). It will be needed later.
Step 1: Installing Knockd
knockd is a port-knocking daemon that listens for connections and opens ports accordingly. We will be using knockd with iptables rules to implement port knocking. Install the required packages as follows:
apt update apt install knockd iptables-persistent
Step 2: Knockd Configuration
Knockd employs a single configuration file, /etc/knockd.conf, to define knocking sequences and other parameters. There are two practical operating modes. The first requires a single knocking sequence to open and close the predefined port, while the other uses separate opening and closing sequences. We will be using the former as it requires less user interaction.
First, backup the existing configuration file:
mv /etc/knockd.conf /etc/knockd.conf.bak
Second, open the configuration file in your text editor:
$EDITOR /etc/knockd.conf
And enter the configuration shown below:
(replace ens18 with your the name of your network interface.)
[options] UseSyslog Interface = ens18 [SSH] sequence = 1000,2000,3000 seq_timeout = 15 tcpflags = syn start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT cmd_timeout = 20
This will instruct knockd to enable traffic to port 22 after receiving the correct knock sequence (1000,2000,3000 in this case), then to re-disable traffic after a 20-second delay. SSH connections will thus only be accepted during this 20-second window.
Next, enable knockd by editing the file /etc/default/knockd:
$EDITOR /etc/default/knockd
And set START_KNOCKD to 1:
START_KNOCKD=1
Save the file and exit. We will also modify the systemd unit for knockd. To do so, create a new unit file to override the default:
$EDITOR /etc/systemd/system/knockd.service
And paste the following:
[Unit] Description=Port-Knock Daemon After=network.target Requires=network.target Documentation=man:knockd(1) [Service] EnvironmentFile=-/etc/default/knockd ExecStartPre=/usr/bin/sleep 1 ExecStart=/usr/sbin/knockd $KNOCKD_OPTS ExecReload=/bin/kill -HUP $MAINPID KillMode=mixed Restart=always SuccessExitStatus=0 2 15 ProtectSystem=full CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN [Install] WantedBy=multi-user.target
Then use the following command to load and enable the new unit:
systemctl daemon-reload systemctl enable --now knockd.service
Step 3: Firewall Rules
At this point, Knockd is ready, but all traffic is enabled through the firewall by default. We will create firewall rules to deny access to port 22/tcp.
The following commands ensure that existing connections are not interrupted.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
The following are rules to drop connections to port 22/tcp:
iptables -A INPUT -p tcp --destination-port 22 -j DROP ip6tables -A INPUT -p tcp --destination-port 22 -j DROP
Then, save the current rule chains for persistence across reboots:
iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6
Step 4: Testing
From a different system, try to start a new SSH session to your server. You should not be able to connect. To perform the knocking sequence, different tools can be used, though we will be demonstrating with knock, the knocking client included with Knockd. Install the knockd package as shown in Step 1 to a different system, then execute the commands:
knock server_ip_address 1000 2000 3000 ssh username@server_ip_address
The SSH connection should now succeed.
Alternative Configuration
Knockd can alternatively be configured to require two distinct sequences for opening and closing network ports. This is useful if you want to keep ports open for extended periods of time. To configure Knockd in the manner, open its configuration file:
$EDITOR /etc/knockd.conf
And replace the existing configuration with the following:
[options] UseSyslog Interface = your_interface [openSSH] sequence = 1000,2000,3000 seq_timeout = 15 tcpflags = syn start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT [closeSSH] sequence = 3000,2000,1000 seq_timeout = 15 tcpflags = syn start_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
Then restart the service to load the new configuration:
systemctl restart knockd.service
Conclusion
Knockd can be an effective solution to brute force attacks, which are very common on SSH and other services. Even though systemd will restart Knockd if it fails, you should always have a backup method of accessing your server if you use port-knocking to hide the SSH port.