Categories
security Sysadmin

Knock Knock … literally this time 😉 – Port Knocking

Hello folks, It’s been a long time since I wrote my last blog. In this blog post, I will show you how you do port knocking to access services on servers such as ssh, mail (postfix), etc securely. Well, we will be literally knocking on ports from the client-side this time 😉

What is port knocking anyway ?

In computer networking, port knocking is a method of externally opening ports on a firewall by generating a connection attempt on a set of prespecified closed ports.

– Wikipedia

English please 😛

In general, you have a secret club where you go and knock on the door in a particular sequence and then club guys identify that It is you and then they let you in. That’s a similar case we are trying to achieve here.

Okay, So let’s say I have a Linux server running ssh service that lets me access my server over port 22. I can configure the firewall running on my server and specify that this port should only be accessible from my home network. The only problem is I can not keep whitelisting my IP address because it is dynamic in nature. Meaning my ISP assigns a new public IP address every now and then. So I am left with only one option i.e to open this port to the entire world.

How about If I can somehow inform my server that this is me, who is trying to connect on the server and now you please open this port temporarily for my IP address and then close once I am connected.

Lets get started and configure server to accept ports knock.

For the demonstration purpose, I am using Amazon Linux 2 running on AWS cloud. I have whitelisted ports 3824,3804,3815 and 3807 in my security group along with port 2601 (temporary) and Port 22 to the entire world.

Prerequisite

  1. knockd daemon
  2. firewalld service
  3. backup port for ssh during configuration
  4. port knocking client/command/script

Add random port such as 2601 to your sshd server config and reload sshd daemon. This port will be used temporarily during the configuration.
Once configured, install firewalld daemon and whitelist the newly added port for the time being. Also, disable ssh standard port 22 since you no longer need to keep it open.

# cd ~
# sed -i '1s/^/Port 22\nPort 2601\n/' /etc/ssh/sshd_config
# systemctl reload sshd
#
# yum install firewalld -y
# systemctl enable firewalld && systemctl start firewalld
# 
# firewall-cmd --add-port=2601/tcp --permanent
# firewall-cmd --reload

;# disconnect from ssh session and reconnect on port 2601
$ ssh -p username@hostname -p 2601

;# Now disable standard ssh port 22 in firewalld daemon
# firewall-cmd --remove-service=ssh --permanent
# firewall-cmd --reload

Download the knockd daemon from github repository or tarball and extract it. Compile the source, install and configure the daemon configuration file.

# yum install libpcap libpcap-devel autoconf libtool -y
# git clone https://github.com/jvinet/knock.git
# cd knock
# autoreconf -fi
# ./configure --prefix=/usr/local
# make && make install

Knockd official documentation provides three examples.

The first one is a simple single knock. Where you knock one sequence of ports and then the port is opened. Another sequence of knock will close the desired port.

The second configuration example opens a port for a while and then closes. This is really good if you want to avoid an attacker that has eaves-dropped on a successful port knock.

The third Example uses sequence files. Here each time sequence is validated a new sequence will be used.

For the sake of this blog, I am using the second example, and here is my custom configuration file.

# cat << EOF > /etc/knockd.conf
[options]
	logfile = /var/log/knockd.log

[opencloseSSH]
	sequence      = 3824,3804,3815,3807
	seq_timeout   = 15
	tcpflags      = syn
	start_command = /bin/firewall-cmd --zone=public --add-rich-rule "rule family="ipv4" source address="%IP%" service name="ssh" accept" 
	cmd_timeout   = 10
	stop_command  = /bin/firewall-cmd --zone=public --remove-rich-rule "rule family="ipv4" source address="%IP%" service name="ssh" accept"
EOF

;# at this point you can start the knockd from shell. knockd by default intercepts packs from eth0 interface. You can change this by specifying -i flag.

In this config file:

  • We tell knockd daemon that we are looking for a port knocking sequence of 3824,3804,3815,3807 (by the way you can also use udp ports in between like 3815:udp) .
  • The time out for the entire sequence is 15 seconds.
  • Knockd should be looking for TCP syn flags in packet.
  • If this sequence is successful, Knockd should execute the command specified by start_command.
  • In our case we are execuing firewall-cmd and adding a rich rule, that whitelist incoming IP address evaluated by knockd internal variable %IP% for SSH port.
  • Once executed, knockd will wait for 10 seconds followed by stop_command will be executed. stop_command removes the rich rule that we just added.

This means that once the port knocking sequence is initialized we have a 10-second window to connect to ssh service on port 22.

Lastly make sure you remove Port 2601 from /etc/ssh/ssdh_config file and firewalld rule, followed by reloading sshd daemon.

Bonus : Add systemd daemon configuration file to run knockd as system service

# cat << EOF > /etc/systemd/system/knockd.service
[Unit]
Description=Knockd Daemon
Documentation=https://zeroflux.org/projects/knock
Requires=network.target
After=network.target

[Service]
User=root
Group=root
ExecStart=/usr/local/sbin/knockd

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload
# systemctl enable knockd && systemctl start knockd

Port knocking from client

We have a 10-second window this means we can not use commands like telnet to manually knock on port and then login to the server using ssh (of course this is not impossible).

I prefer to use nc (net cat) or nmap command.

Here is the simple snippet of shell script knock-knock.sh

#!/bin/bash

for port in 3824,3804,3815,3807
do
	nc -W 1 -w 1 $1 $port
done

ssh -i your_keypair username@$1

;# you can call this shell script as
$ chmod u+x knock-knock.sh
$ ./knock-knock.sh server_ip_here 

The -W (capital) on nc command will wait for only the 1st TCP packet -w (small) will wait for 1 second. “For loop” coordinates for quickly executing this port sequence.

Alternatively, you can use nmap.

$ nmap YOUR_SERVER_IP -p 3824,3804,3815,3807 -r --max-retries 0 --max-parallelism 1 -sT --scan-delay 200ms --max-rtt-timeout 200ms -Pn

$ ssh -i yourkey username@YOUR_SERVER_IP

Here is the snapshot from my system.

That’s it for this blog post. By the way, do you think you can write your own shell script which acts as similar to knockd daemon using tcpdump command?

6 replies on “Knock Knock … literally this time 😉 – Port Knocking”

Written in a very unique and interesting way. I never felt sleepy and bored while reading your blog. Concept explained really well 👏 👍

Leave a Reply

Your email address will not be published. Required fields are marked *