Firewall administrators are challenged to balance flexibility and security when designing a comprehensive rule set. A firewall should provide protection against malfeasants, while allowing trusted users to connect. Unfortunately, it is not always possible to filter out the bad guys, because filtering on the basis of IP addresses and ports does not distinguish connecting users. Bad guys can and do come from trusted IP addresses. Open ports remain a necessary vulnerability: they allow connections to applications but also may turn into open doors for attack. This article presents a new security system, termed port knocking, in which trusted users manipulate firewall rules by transmitting information across closed ports.
Briefly, users make connection attempts to sequences of closed ports. The failed connections are logged by the server-side packet filtering firewall and detected by a dæmon that monitors the firewall log file. When a properly formatted knock sequence, playing the role of the secret used in the authentication, is received, firewall rules are manipulated based on the information content of the sequence. This user-based authentication system is both robust, being mediated by the kernel firewall, and stealthy--it's not possible to detect whether a networked machine is listening for port knocks. Port knocking does not require any open ports, and it can be extended to transmit any type of information encoded in a port sequence.
In commonly deployed firewalls, filtering is done either by the IP address of the connecting host or by the port to which this host is connecting. Firewalls examine and interact with packets before any user authentication takes place; therefore, they do not discriminate amongst the users making the connection. It is expected that once the firewall has approved the packet and allowed it to enter the network, downstream applications will handle user authentication. Normally, this provides a sufficient balance between protection and flexibility. Some IP ranges, say cracker-friendly Internet cafés, may be closed completely to incoming traffic, while hosts in other IP ranges may be allowed to connect to ports otherwise unavailable to the general public (proprietary/sensitive applications). Unfortunately, this type of IP-based filtering has the potential to lock out trusted users from your system. Flexibility is limited by the fact that nobody from the blocked IP ranges can connect, regardless of their trust statuses. At the same time, protection is undermined by the fact that anyone from the blocked IP range physically can travel and connect from an unfiltered host.
In the end, as long as ports remain open, network applications are susceptible to attack. Using intrusion detection systems and keeping applications up to date can go a long way towards providing protection, but they do so against only known, derivative or anticipated attacks.
To eliminate the risk associated with publically open ports, port knocking provides an authentication system that works across closed ports. The use of these ports, however, has to be subverted because all packets are denied. Fortunately, in most firewalls that perform even the most rudimentary logging, information already is flowing across closed ports in the form of entries in a log file indicating connection attempts.
Consider the following example. A handful of ports (100-109) are configured to deny all traffic--no ICMP error packets are sent back to the connecting client--and all attempted connections are logged. In this example, the firewall IP is IPF and the connecting client IP is IPC. The appropriate ipchains command to close the ports and log connections is:
ipchains -A input -p tcp -s 0/0 -d IPF/32 100:109 -j DENY -l
A user attempts to connect from IPC to the following firewall ports in sequence: 102,100,100,103. From the point of view of the user, the connections fail silently. On the firewall, though, the 102,100,100,103 number sequence has been recorded.
Feb 12 00:13:26 ... input DENY eth1 PROTO=6 IPC:64137 IPF:102 ... Feb 12 00:13:27 ... input DENY eth1 PROTO=6 IPC:64138 IPF:100 ... Feb 12 00:13:27 ... input DENY eth1 PROTO=6 IPC:64139 IPF:100 ... Feb 12 00:13:28 ... input DENY eth1 PROTO=6 IPC:64140 IPF:103 ...
The knock sequence appears in the firewall log, and the user has transmitted data across the closed ports.
Any implementation of the port knocking system needs to provide some basic functionality. First, some way to monitor the firewall log file needs to be devised. A simple Perl application that tails the file is presented in Listing 2, discussed more fully later in the article. Second, a method is required to extract the sequences of ports from the log file and translate their payload into usable information. In this step it is important to be able to (a) detect when a port sequence begins and ends, (b) correctly detect a port sequence in the presence of spurious connection attempts that are not part of the sequence and (c) keep track of multiple port sequences arriving at the same time from different remote IPs. The encoding used to generate the port sequence can be designed to minimize the length of the sequence. For example, the sequence 100,102 could correspond to one or a series of predefined operations (for example, open port ssh/22 for 15 minutes for a specific IP and then close the port). Finally, once the information is derived from the sequence, the implementation must provide some way to manipulate the firewall rules.