![]() |
Site Archive (Complete) | |||
|
ABOUT US |
CONTACT |
ADVERTISE |
SUBSCRIBE |
SOURCE CODE |
CURRENT PRINT ISSUE |
NEWSLETTERS
|
RESOURCES
|
BLOGS
|
PODCASTS
|
CAREERS
|
||||
November 01, 2004
Practical Secure Port KnockingJohn Graham-Cumming
Using port knocking, you can increase security by leaving sensitive network ports closed until they are opened with a secret "knock."
John is vice president of engineering at Electric Cloud, which focuses on reducing software build times. He can be contacted at jgc@ electric-cloud.com.
Last year, Martin Krzywinski described a technique for stealthily communicating with a computer (see "Port Knocking: Network Authentication Across Closed Ports," Sys Admin magazine, June 2003). The idea was that open ports on a machine invite attack. If you leave a machine on the Internet with an SSH daemon running on port 22, it's a simple matter for attackers to use port scanners like nmap (http://www.insecure.org/nmap/) to discover that the port is open and then try to attack it.
Krzywinski suggested that sensitive ports should be left closed until opened using a secret knock. The knock consists of sending TCP SYN packets (the first packet sent when opening a TCP connection) to a sequence of closed ports on the target machine. Firewall software records in a log file the failed connection attempts and software watching the firewall log checks for a specific sequence of ports and enables/disables a service. For example, with the correct knock, an SSH daemon could start waiting for connections, or the firewall could be reconfigured to allow connections from the host that knocked.
Since a knock is just a sequence of attempted TCP connections, programs such as telnet can be used to manually generate it. For example, to knock on ports 42, 196, and 69 of 192.168.0.3, do:
Imagine that Linux host 192.168.0.3 is running an SSH daemon on port 22, but the iptables firewall (http://www.netfilter .org/) has been set to drop and log every incoming TCP packet, thus making access to the SSH daemon impossible:telnet 192.168.0.3 42 telnet 192.168.0.3 196 telnet 192.168.0.3 69
This tells iptables to create a new chain called LOGNDROP, then pass all incoming TCP packets to the chain where they are first logged (most likely to /var/log/messages) with the prefix FIREWALL: (for easy grepping), then dropped.
The use of the action DROP means that TCP packets are not acknowledged in any way. The packet is simply discarded. The host machine will not even generate an ICMP "port unreachable" packet and the host appears to be switched off, but the connection attempt has been logged. To outsiders, the system appears to be inoperative, but the log file tells a different story.
An application watching /var/log/messages sees entries such as those in Example 1 if a knock is made against ports 42, 196, and 69 from host 192.168.0.5. The same application could process the ports knocked to decide to add or remove entries in iptables, thereby opening or closing ports. For example, the correct knock on 42, 196, 69 could result in the firewall opening port 22 just for host 192.168.0.5 for SSH access with the iptables command:
Port knocking has three fundamental ideas behind it:iptables -I INPUT -p tcp -s 192.168.0.5 -- dport 22 -j ACCEPT
which prints out all TCP SYN and SYN/ACK packets. For example, intercepted knocks on 42, 196, and 69 would look like Example 2. A Perl script (Listing 1) can quickly parse tcpdump's output to determine which SYN packets received a SYN/ACK (hence, were real connections) and which were silently dropped (and hence could be a knock), then produce the output:tcpdump -t -n '(tcp[13] == 2) or (tcp[13] == 18)' Once the knock is known, it can be repeated by a third party to open the SSH port for their use at any later time. Because of this vulnerability, encryption of the knock is essential (for more information on encryption techniques, see http://www.portknocking.org/). The knock needs to be nonreplayable (that is, eavesdroppers can't reuse the knock for their own use), nonspoofable (eavesdroppers can't reuse the knock from a different IP address), and should not be easily decodable.Knock on 192.168.0.3:42 Knock on 192.168.0.3:196 Knock on 192.168.0.3:69 TumblerThe Tumbler protocol (named for the parts of a lock that tumble into place when the right key is inserted) implements the spirit of port knocking with robust security using a well-known hashing algorithm. Tumbler provides protection against replay attacks (the knock is timestamped and cannot be reused after a short interval) and spoofing (the knock can only be used from a specific IP address). In addition to the protocol, a Perl implementation is available under the General Public License at http://tumbler.sf.net/. Of course, there's no reason whyTumbler has to be implemented in Perlthe protocol is simple and could easily be built into other applications (for example, SSH could include a --tumbler option to perform the appropriate knock before connecting). The protocol consists of a single UDP packet in the form:where <v> is the protocol version number, currently 1, and <knock> is a hexadecimal string containing the knock. For example, the UDP packet might contain:TUMBLER<v>: <knock> There is no response to the message. Either the process listening for Tumbler messages accepts it or it is silently dropped. The <knock> is created by hashing the following three pieces of information using the SHA256 algorithm (http://csrc.nist.gov/CryptoToolkit/tkhash.html):TUMBLER1:844c17eee03d848cc0a60e90f608d5ea11f417d 9bf0d2c1af2b5
ImplementationIn the Perl implementation (available online at http://www.tpj.com/), a script named "tumbler" sends the knock using Example 3 (with $secret containing the user's secret password). It grabs the Zulu time by calling gmtime, gets the machine's IP address in dotted format by calling inet_ntoa (on an IO::Socket called $socket), then hashes the message using sha256_hex (which is part of the Perl module Digest::SHA; http://search.cpan.org/ ~mshelor/DigestSHA5.02/SHA.pm) and returns a hex string containing the SHA256 hash. Finally, it sends a single UDP packet containing the Tumbler message. The receiving machine runs another Perl script named "tumblerd" (also available online), which is configured through the configuration file tumblerd.conf to listen on a UDP port for Tumbler messages and perform commands. In Listing 2, tumblerd has been configured to allow SSH connections once a knock with the password open-pAsSwOrD has been made, and there's even a knock that closes the port again (password close-pAsSwOrD). For example, to open the SSH port, the remote user runs:or alternatively:tumbler --open tumbler://open-pAsSwOrD@host:8675/ and then types in the secret password open-pAsSwOrD. The tumblerd runs through all the configured secrets looking for a hash match and, when it finds one, it runs the appropriate command. A simple shell script containing three commands could establish an SSH connection to the host after opening the port with a knock and close the port again when the SSH connection is complete:tumbler --open tumbler://host:8675/ #!/bin/bash tumbler --open tumbler://open-pAsSwOrD@host:8675/ ssh host tumbler --open tumbler://close-pAsSwOrD@host:8675/ Security PropertiesTumbler clearly shares with port knocking the idea that ports are closed by default, and the use of a shared secret to open ports. To maintain the "vow of silence," tumblerd does not respond to packets sent, but it is possible to discover the existence of tumblerd using nmap UDP scanning if the firewall is not configured to drop unknown UDP packets. To run a UDP scan a host with nmap, type:This detects the tumblerd daemon running:nmap -sU host -p1-65535 nmap UDP scanning works by sending a packet to each port scanned and looking for the ICMP "port unreachable" message sent when the port is closed. If there's no port unreachable reply, then the port is open. To prevent that from happening, configure iptables to drop all UDP packets except those destined for tumblerd:Starting nmap 3.30 ( http://www.insecure.org/nmap/ ) Interesting ports on host (192.168.0.3): Port State Service 8765/udp open unknown Dropping the packets means that they are silently discarded. Tumbler guards against replay attacks, where eavesdroppers intercept Tumbler packets and try to reuse them in two ways:iptables -A INPUT -p udp --dport 8675 -j ACCEPT iptables -A INPUT -p udp -j DROP
tcpdump 'dst port 8675' Other ImplementationsTumbler is just one implementation of the port knocking idea. In addition to reading http://www.portknocking.org/, check out the following interesting projects: doorman (http://doorman .sourceforge.net/) and knockd (http://www.zeroflux.org/knock/). Most interesting of all is cd00r (http://www.phenoelit.de/stuff/ cd00rdescr.html), which was intended for use in malware. An academic look at port knocking comes in the form of a research paper from Intel Research (http://www.intelresearch.net/ Publications/Berkeley/012720031106_111.pdf). TPJListing 1 #!/usr/bin/perl -w
use strict;
my @knocks;
while ( <> ) {
my $packet = $_;
$packet =~ /^((\d+\.){3}\d+)\.(\d+) > ((\d+\.){3}\d+)\.(\d+)/;
my ($src_ip,$src_port,$dest_ip,$dest_port ) = ($1,$3,$4,$6);
if ( $packet =~ / ack / ) {
@knocks = grep( !/^$src_ip:$src_port$/, @knocks );
} else {
push @knocks, "$dest_ip:$dest_port";
}
}
foreach my $k (@knocks) {
print "Knock on $k\n";
}
Back to articleListing 2 # The common section contains configuration options for the tumblerd daemon, # here we set the UDP port to listen on to 8675 and a log file [common] port = 8675 log = /var/log/tumblerd.log # Each door that a user can knock on is defined by a unique [door-X] section, # the first section is for opening the SSH port, and second for closing # # Each door has a secret (i.e. the password for this # door that is part of the knock) and a command to execute. # # In the command it's possible to use the macros %IP% for the IP address of # the person who knocked and %NAME% for the name of the door (in the # first door here the name is open-ssh) [door-open-ssh] secret = open-pAsSwOrD command = iptables -I INPUT -p tcp -s %IP% --dport 22 -j ACCEPT [door-close-ssh] secret = close-pAsSwOrD command = iptables -D INPUT -p tcp -s %IP% --dport 22 -j ACCEPTBack to article
|
|
||||||||||||||||||||||||||
|
|