Single Packet Authorization with Port Randomization

01 June, 2008

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 11.1.1.1, and the fwknop client runs on the spaclient system
with IP 12.2.2.2. 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):

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 11.1.1.1 over UDP port
12345 (instead of the default of 62201), one could use the following
command:

$ fwknop -A tcp/22 -R -D 11.1.1.1:12345

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 install.pl 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).