Introduction

This very short article is about port knocking and iptables. Port knocking allows a specific port to be opened when a sequence of connection attempts on predefined ports are made. The correct sequence of “knocks” will dynamically open the desired port temporarily so that a connection can be made on the desired port.

In this article we will use port 22 as the port to hide with four (4) UDP ports to knock.

Code

Using iptables, the following commands will create several chains, INTO-PHASE2, INTO-PHASE3, and INTO-PHASE4. Each chain will have several rules appended. Specifically a match is used to make up the condition under which the next step is invoked. If the given sequence of UDP ports are knocked in sequence port 22 on eth0 interface will open for five (5) seconds.

## Define port knocking
sudo iptables -N INTO-PHASE2
sudo iptables -A INTO-PHASE2 -m recent --name PHASE1 --remove
sudo iptables -A INTO-PHASE2 -m recent --name PHASE2 --set
sudo iptables -A INTO-PHASE2 -j LOG --log-prefix "INTO PHASE2: "
sudo iptables -A INTO-PHASE2 -j DROP

sudo iptables -N INTO-PHASE3
sudo iptables -A INTO-PHASE3 -m recent --name PHASE2 --remove
sudo iptables -A INTO-PHASE3 -m recent --name PHASE3 --set
sudo iptables -A INTO-PHASE3 -j LOG --log-prefix "INTO PHASE3: "
sudo iptables -A INTO-PHASE3 -j DROP

sudo iptables -N INTO-PHASE4
sudo iptables -A INTO-PHASE4 -m recent --name PHASE3 --remove
sudo iptables -A INTO-PHASE4 -m recent --name PHASE4 --set
sudo iptables -A INTO-PHASE4 -j LOG --log-prefix "INTO PHASE4: "
sudo iptables -A INTO-PHASE4 -m recent --rcheck --name PHASE4 -j LOG --log-prefix "(OPEN PORT 22) - "
sudo iptables -A INTO-PHASE4 -j DROP

## if you want to knock using tcp packets uncomment this line:
#sudo iptables -A INPUT -m recent --update --name PHASE1

## Define knocking sequence: knock on ports and then open SSH port for 5 seconds
sudo iptables -A INPUT -p udp --dport 23456 -m recent --set --name PHASE1
sudo iptables -A INPUT -p udp --dport 34567 -m recent --rcheck --name PHASE1 -j INTO-PHASE2
sudo iptables -A INPUT -p udp --dport 45678 -m recent --rcheck --name PHASE2 -j INTO-PHASE3
sudo iptables -A INPUT -p udp --dport 56789 -m recent --rcheck --name PHASE3 -j INTO-PHASE4

sudo iptables -A INPUT -p tcp --dport 22 -i eth0 -m recent --rcheck --seconds 5 --name PHASE4 -j ACCEPT

The following script can be used to open port 22 where HOST is the ip address of the sshd:

#!/usr/bin/env bash
set -euxo pipefail

IFS=$'\n\t'
HOST='xxx.xxx.xxx.xxx'

PORT1=23456
PORT2=34567
PORT3=45678
PORT4=56789

echo "KNOCK1"
echo -n "*" | nc -w1 -u $HOST $PORT1

echo "KNOCK2"
echo -n "*" | nc -w1 -u $HOST $PORT2

echo "KNOCK3"
echo -n "*" | nc -w1 -u $HOST $PORT3

echo "KNOCK4"
echo -n "*" | nc -w1 -u $HOST $PORT4

echo "CONNECT"

Final words

Port knocking is a great way to protect your ports. Specifically for sshd, which is usually kept open. An additional enhancement for security purposes would be to change the port that sshd uses.