Port Knocking The Easy Way

I had implemented port knocking before with linux daemons and knocking clients but this requires installing software that is always running and consuming memory and processor resources. If you are using a Virtual Private Server –as I am–, you can’t afford to waste a single megabyte of memory. Therefore, you begin looking for creative alternatives that minimize the load on the server.

Some time ago, I found a curious implementation of port knocking using iptables. So, if you already have iptables installed on your (virtual) machine, you can get rid of an always-running daemon.

You can find the original script here, or get the more complete script I’ve made.

#!/bin/bash

#
# Port Knocking server configuration. It closes all ports but the webserver one.
# When the correct sequence of ports is detected (1000. 2000. 3000. 4000), the
# SSH port is opened for 5 seconds to allow connections.
#

# Erase all the rules
iptables -F

# Close all incoming connections
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT


# Open the web server port to the public
iptables -A INPUT -m state --state NEW -p TCP --dport 80 -j ACCEPT

# Allow the loopback interface (mysql, ...)
iptables -A INPUT -i lo -j ACCEPT


# Port Knocking
###############
# Original Script http://pub.ligatura.org/fs/netfilter/misc/portknock_multi
#
# Netfilter/IPtables - example of multiple-port knocking
# Note: Knock ports to open SSH port for 5 seconds.

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

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

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

iptables -A INPUT -m recent --update --name PHASE1

iptables -A INPUT -p tcp --dport 1000 -m recent --set --name PHASE1
iptables -A INPUT -p tcp --dport 2000 -m recent --rcheck --name PHASE1 -j INTO-PHASE2
iptables -A INPUT -p tcp --dport 3000 -m recent --rcheck --name PHASE2 -j INTO-PHASE3
iptables -A INPUT -p tcp --dport 4000 -m recent --rcheck --name PHASE3 -j INTO-PHASE4

iptables -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name PHASE4 -j ACCEPT
view raw doorman.sh This Gist brought to you by GitHub.

On the client side, I use a small bash function that performs the knocks and connects to the SSH server. The only requirement it needs is the netcat utility.

#!/bin/bash

# SSH Connection Port Knocker
#
# 1 - Append this code to your .bashrc or .bash_profile file
# 2 - Create a .portknocks file in your home directory with a list like
# host1 port1
# host1 port2
# ...
# host1 portN
# host2 port1
# ...
# 3 - You must open a new terminal session to use the new function
# 4 - Use it as you would use the ssh command
# ssh user@server => pssh user@server
#
# It accepts the usual options of the SSH program

pssh() {

  while getopts "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:W:XYy" FLAG
  do
true
done

HOST=${@:$OPTIND:1}
  HOST=${HOST#*@}
  CNT=1

  cat ~/.portknocks | grep ^$HOST | awk '{ for(i=2; i <= NF; i++) printf "%s\n", $i}' | \
  while read PORT
  do
echo "Knocking $HOST ($CNT)"
    nc -w 1 $HOST $PORT & sleep 0.5 &&
    ((CNT++))
  done

ssh $*
}
view raw pssh.sh This Gist brought to you by GitHub.

Enjoy it!

This entry was posted in Code and tagged , , . Bookmark the permalink.

One Response to Port Knocking The Easy Way

  1. Pingback: Using SCP Port Knocking Remote Hosts | blog.franciscodavid.eu