Michael Rash, Security Researcher

Single Packet Authorization with Port Randomization

Single Packet Authorization with Port Randomization After two months of development, the 1.9.4 release of fwknop is available for download. This release introduces new functionality that has implications for hardening both fwknop SPA communications and the follow-on connections that client programs make (such as SSH). Specifically, the 1.9.4 release adds two port randomization options to 1) send the SPA packet over a random port between 10,000 and 65,535 (requires updating the default PCAP_FILTER variable on the fwknopd server side), and 2) select a random port that is used as the destination port in a NAT operation on the fwknopd server system. These two options can be used individually or together, and are enabled with two new command line options, --rand-port and --NAT-rand-port respectively, to the fwknop client (see examples below).

The inspiration for adding this functionality came from a post to the "Documentation, Tips & Tricks". Gentoo forum, and I have credited John Brendler with the idea. In response to John's post, I would like to mention however that all Port Knocking / Single Packet Authorization implementations suffer from "piggy-back exploits", including those that select random ports for SPA communications or for NAT operations against follow-on sessions. A "piggy-back exploit" is where an attacker takes advantage of the fact that a firewall rule inserted by a PK/SPA system accepts a connection from an IP address to a destination port specified by the SPA packet(s). So, if the attacker can spoof packets from this source IP, or if the attacker happens to be on the same internal network as the SPA client (and hence sends connections out through the same NAT device), then the firewall rule will accept these packets just as though they originated from the legitimate SPA client system. If an attacker is in a privileged position and can sniff the legitimate session as it is initiated, then one can envision an automated attack that spoofs packets from the same source IP and directs them at the same service. Further, such an "attack" can be made just by watching outgoing connections without paying any attention whatsoever to whether or not a set of SPA packets are sent first - it doesn't matter if the real connection is made to a random translated port on the SPA system; the attacker can see this port in the real connection itself.

Now, should you be concerned about such a piggy-back attack? Not really. First, if the attacker is not going through the same NAT device as the real connection, then any response to a spoofed packet will go back to the spoofed source - not back to the attacker. So, for TCP connections, unless the attacker can effectively perform a sequence prediction attack an existing connection (and even then that is of little use against an encrypted application layer protocol such as SSH), this is not very effective. Second, even if an attacker is behind the same NAT device as the SPA client, just being able to access the targeted service over TCP/IP does not imply an automatic vulnerability; SPA is an additive measure to whatever existing security mechanisms are already in place (barring a vulnerability in libpcap itself in the SPA server for example). Third, there are an awful lot of networks out there to which an attacker will not have such privileged access, and therefore not be in a position able to sniff anything useful. Forth, fwknop minimizes the opportunity for an attacker to conduct a piggy-back attack by maintaining a small window of time (30 seconds by default) for any new firewall rules after receiving a valid SPA packet. By using a connection tracking mechanism built into iptables or ipfw, any connection established during the accept window is allowed to remain open but all attempts to create a new connection must first preceeded with a new SPA packet in order to gain access.

Finally, although port randomization is an enhancement, fwknop has had the ability for a long time to allow the user to select the destination port for SPA packets with the --Server-port argument as well as the destination port for a NAT'd connection to an internal system. Hence, fwknop SPA packets are not always sent over udp/62201. But, I agree that it is useful to add the port randomization features that John Brendler suggested, and this is why I've implemented them in fwknop. Randomizing the SPA destination port along with the destination port of the follow-on connection makes traffic analysis more difficult.

Now, let us see the new --rand-port and --NAT-rand-port options in a practical example. We'll assume that the fwknopd server is at hostname spaserver with IP, and the fwknop client runs on the spaclient system with IP We ultimately want to gain access to SSHD on the spaserver system, and we assume that iptables is configured in a default-drop stance for all attempts to communicate with SSHD. Also, there is no requirement to necessarily attempt to gain access only to an SSHD instance running on an internal server via a forwarded port - the iptables PREROUTING chain can forward a port to a local socket as well (based on a routing calculation for the destination IP), and on the fwknop client command line we use the --NAT-local argument for this.

Because the --rand-port option sends the SPA packet over a random destination port, we first need to set the PCAP_FILTER variable as follows in the /etc/fwknop/fwknop.conf file: [spaserver]# vi /etc/fwknop/fwknop.conf
PCAP_FILTER udp dst portrange 10000-65535;

[spaserver]# /etc/init.d/fwknop restart
[+] knopwatchd is running (pid: 17584), stopping daemon
[+] knoptm is running (pid: 17582), stopping daemon
[+] fwknopd is running (pid: 17580), stopping daemon
Starting the fwknop daemons.
With the fwknopd server up and running, we now use the fwknop client to gain access to SSHD on the spaserver system via a randomly selected NAT'd port (and we show that SSHD is never accessible over the standard TCP port 22 even from the spaclient system):
[spaclient]$ nmap -sT -n -P0 -p 22

Starting Nmap 4.20 ( ) at 2008-06-02 01:48 EDT
Interesting ports on
22/tcp filtered ssh

Nmap finished: 1 IP address (1 host up) scanned in 12.017 seconds

[spaclient]$  fwknop -A tcp/22 --NAT-local --NAT-rand-port \
--rand-port -R -D

[+] Starting fwknop client (SPA mode)...
[+] Requesting NAT access for randomized port: 16791
    Resolving external IP via:
    Got external address:

[+] Enter an encryption key. This key must match a key in the file
    /etc/fwknop/access.conf on the remote system.

Encryption Key:

[+] Building encrypted Single Packet Authorization (SPA) message...
[+] Packet fields:

        Random data:    4846125760033285
        Username:       mbr
        Timestamp:      1212386108
        Version:        1.9.4
        Type:           5 (Local NAT access mode)
        NAT access:,16791
        SHA256 digest:  ZyWG+nRGYMfWFssJuOy7bhGmJHpHia6T1igaNnVVhqI

[+] Sending 206 byte message to over udp/52949...
    Requesting NAT access to tcp/22 on via port 16791

[spaclient]$  ssh -p 16791 mbr@
mbr@'s password:
The above output shows that the client system indeed has access to the spaserver system via TCP port 16791, which is forwarded to the local SSH daemon. In the /var/log/messages file, fwknopd has written the following messages to syslog: [spaserver]# tail /var/log/messages
Jun 2 01:54:16 spaserver fwknopd: received valid Rijndael encrypted packet from:, remote user: mbr, client version: 1.9.4 (SOURCE line num: 151)
Jun 2 01:54:17 spaserver fwknopd: add FWKNOP_PREROUTING -> to 22) DNAT rule 30 sec
Jun 2 01:54:17 spaserver fwknopd: add FWKNOP_INPUT -> ACCEPT rule 30 sec
Jun 2 01:54:58 spaserver fwknop(knoptm): removed iptables FWKNOP_PREROUTING DNAT rule for ->, 30 sec timeout exceeded
Jun 2 01:55:11 spaserver fwknop(knoptm): removed iptables FWKNOP_INPUT ACCEPT rule for ->, 30 sec timeout exceeded
In closing, here is an abbreviated version (the randomization options are not duplicated here) of the fwknop-1.9.4 ChangeLog:

  • Added the ability to specify the port that SPA packets are sent over with the fwknop client by using the syntax "<host|IP>:<port>". So, for example, to have the client send an SPA packet to over UDP port 12345 (instead of the default of 62201), one could use the following command:

    $ fwknop -A tcp/22 -R -D

  • Bugfix to add a check for "keep-state" in ipfw policies in addition to the existing "check-state" check (noticed by Sebastien Jeanquier).
  • Updated the script to try to determine the OS type as early as possible during the install process.
  • Added the MIN_SPA_PKT_LEN variable with 160 (bytes) as the default. This allows fwknopd to ignore packets that are not at least this many bytes (including packet headers) before any decryption attempt is made.
  • Added --time-offset-plus and --time-offset-minus args to the fwknop client command line. This allows the time stamp within an SPA packet to be influenced without setting the system clock (which normal users cannot usually do). This is useful for when the client and server systems have clocks that are out of sync.
  • Bugfix on Ubuntu systems to make sure that the fwknop init script is installed with a priority of 99 instead of 20 - this puts fwknop as late as possible within the boot sequence so that the system is ready to run fwknop.
  • Bugfix to not open ports that are not specifically requested in an SPA packet even if those ports are listed in the OPEN_PORTS variable in the access.conf file.
  • Updated to version 5.47 of the Digest::SHA module.
  • Updated to version 0.7 of the IPTables::ChainMgr module (includes perldoc documentation).
  • Updated to version 0.6 of the IPTables::Parse module (includes perldoc documentation).
  • Added NAT, port randomization, and and time offset option discussions to fwknop(8) man page.