This page looks best with JavaScript enabled

Portknocking

 ·  🎃 kr0m

As many of you may know, a TCP connection is not considered established until a series of packets have been exchanged, the well-known TCP-Handshake, which consists of an initial SYN packet, a response SYN/ACK packet, and a final ACK packet. At that moment, the bound application to that port is responsible for sending information.

Portknocking consists of using this type of traffic to perform certain operations on the server, so that by combining connection attempts, we can apply firewall rules or execute any other command.

The first thing we will do is install the portknocking service on the server:

emerge -av net-misc/knock

Now we perform the configuration according to our needs. In my case, when I send the magic combination 7000 8000 9000, I will allow access via ssh by inserting an iptables rule for this purpose:

vi /etc/knockd.conf

[options]
        logfile = /var/log/knockd.log
[openSSH]
       sequence    = 7000,8000,9000
       seq_timeout = 5
       command     = /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT
       tcpflags    = syn
[closeSSH]
       sequence    = 9000,8000,7000
       seq_timeout = 5
       command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
       tcpflags    = syn

We finish the configuration by indicating on which interface knockd should remain listening:

vi /etc/conf.d/knock

IFACE="eth0"
OPTS=""

We start the service and add it to the startup:

/etc/init.d/knock start
rc-update add knock default

We insert the ACL that will be responsible for blocking ssh traffic if the portknock has not been sent:

iptables -I INPUT 1 -p tcp –dport 22 -j DROP

If we have the default rules to block traffic, we must open the ports used by knockd. Otherwise, iptables, which is at the kernel level, will intercept the traffic before knockd, and it will be as if the knock had never been sent:

iptables -I INPUT 1 -p tcp –dport 7000 -j ACCEPT
iptables -I INPUT 1 -p tcp –dport 8000 -j ACCEPT
iptables -I INPUT 1 -p tcp –dport 9000 -j ACCEPT

We can see the logs in /var/log/knockd.log:

tail -f /var/log/knockd.log

On the client side, we will have to install some software capable of generating the expected traffic for knockd, in my case netcat, but any other would be equally valid:

emerge -av net-analyzer/netcat

We generate the expected traffic for knockd:

nc -z A.B.C.D 7000 8000 9000

On the server, we can see how the firewall rule has been applied:

tail -f /var/log/knockd.log

[2014-10-30 16:46] E.F.G.H: openSSH: Stage 1
[2014-10-30 16:46] E.F.G.H: openSSH: Stage 1
[2014-10-30 16:46] E.F.G.H: openSSH: Stage 2
[2014-10-30 16:46] E.F.G.H: openSSH: Stage 3
[2014-10-30 16:46] E.F.G.H: openSSH: OPEN SESAME
[2014-10-30 16:46] openSSH: running command: /sbin/iptables -I INPUT 1 -s E.F.G.H -p tcp --dport 22 -j ACCEPT

Also, if we check the iptables rules:

iptables -L -n

ACCEPT     tcp  --  E.F.G.H         0.0.0.0/0            tcp dpt:22

When we have finished performing administrative tasks, we can close the gap by:

nc -z A.B.C.D 9000 8000 7000

NOTE: One possible way to increase the security of this system could be to reconfigure the port combination according to the time slot or using a custom algorithm. This way, a valid combination may no longer be valid after X time.

There is no doubt that this technique can be very useful in environments where paranoia prevails over functionality. This way, the service would only be exposed for a limited time to a specific source IP ;)

If you liked the article, you can treat me to a RedBull here