SPA - Single Packet Authentication In June of 2003 an article in SysAdmin Magazine [1] talked about an idea for securing machines, but still allowing them to be accessible. The idea is authentication across closed ports. Since the article, the idea of "port knocking" has been of particular interest to parts of the computer security industry [2]. This paper will attempt to point out some minor flaws in the port knocking idea and present another way of approaching this concept in a robust and secure way. Since his article in SysAdmin, Martin Krzywinski [3] has started a website devoted to this idea. He has some proof of concept code and a detailed explanation of port knocking as well as a rebuttal to some of the attacks port knocking has received [4]. On his website, Martin does give credit to at least two other project before that have addressed this concept with code. Unfortunately at the time of this writing, Martin's web site returned a 404 "File Not Found" page instead of the page he says "list[s] other projects, such as cd00r and SAdoor". [5][6] Port Knocking, and other implementations, have said to be security through obscurity (STO) [7], and therefore a bad thing. While it is true that port knocking is security through obscurity, this is not the worst of its problems, and may not really be a problem at all [4]. The issue with port knocking and all the implementations examined thus far is that they are noisy, and easily re-playable. First, let us take a look at the concepts more closely. The idea behind port knocking is that all the ports are "closed" on a host. We can do this by having all daemon/services turned off, bounded to a non-routable IP, or firewalled. The reason we do not want to have anything listening on the machine is just as simple as, if there is nothing listening, we are less likely to have a vulnerability available for someone to take advantage of. The problem comes in that we have a machine we want to gain access to, but we don't allow anything to connect. Using port knocking we can send a sequence of packets, in a specific order, to cause the daemon that is either sniffing all the traffic, but not bound to nay port, or tailing a firewall log file, to open a port, start a daemon, or what ever else we might want the program to do. Because the port knocking daemon is not bound to any port a port scanner, such as nmap [8], will not detect any open ports. Let's take this picture one step further. If we have a server we want to access via SSH, for instance, but we don't want SSH listening, or available to the general public, this might be a good system to choose. It seems logical that we would allow access from known points that would not change. So let's say we want to access our host from a non-static location, like public access points (coffee house). Now we are on a truly hostile network, where we know nothing about its administrators, their motives or intentions. If we use port knocking or one of the other packages we have looked at, the packets can simply be replayed from anywhere to gain the same access. The sequence is static and the encryption used does not verify anything unique, it is simple a pre-shared key. So if a "bad guy" owns the open network, and he sniff someone's traffic, they will see that some set of "random" packets where sent then the victim sshed into their remote host. If the bad guy scans the host later, he will not see any ports open, but he also knows the victim sshed into said host. So what if I replay the same packets? On the implementations we have seen, replaying the same packets causes the daemon to respond the same way [9]. The initial fix was just to change the sequence of packets each time, but then you have to have a way of generating the sequences. If you use a set sequence, with enough traffic, the sequence could be determined. Taking a step back and looking at the problem again, the idea of a single packet, encrypted with a unique key that would only be played one time (one time password), with simple information inside was decided to be the best approach. If we use a sequence number, for example, we are able to start off with 2 pre-shared secrets. The first is the initial sequence number and the second is a pass phrase. If we encrypt our payload with these 2 things, and include the next sequence number within the payload, to be updated on successful verification, we have the ability to have random one time passwords that change with each successful connection. Using these key pieces of information and concepts, we can impliment an initial proof of concept Single Packet Authentication code. The SPA daemon is able to sniff all traffic and is not limited to a specific number of ports. The configuration allows for multiple users, giving each user a unique ID, which can be the same as the Unix UID. Each UID has a unique shared secret or pass phrase and an initial sequence number, which is a 16bit number. Within the single packet we are encrypting 2 things, the port and the next sequence number. To decrypt the packet you must have the current sequence number and the shared secret. The daemon looks at the last 37 bytes of each packet. The first 5 in this payload is the UID to tell the daemon which sequence number and shared secret to use to decrypt the last 32 bytes. One idea was to place the UID in the TCP headers, but it was decided to move it to part of the data field as we can inject this on the tail of a valid packet, or we can create large packets with random data to further the security through obscurity. Once the packet is received and decrypted, the sequence number is updated for the next time SPA is used by this user and the port is opened, or the daemon is started (other things could be done as well, with config options set for specific commands to be run when certain ports are requested to be opened). Once the port is open to the originating IP, the daemon would generate a packet with the new sequence number and port, encrypted with said sequence number and shared secret to tell the client the command was successful. Once the 'ACK' packet is sent the traffic is monitored on that port, and when there is a lack of traffic for a set timeout, the port is closed, or the daemon is stopped. The client for SPA would generate the packet, update the sequence number and launch the appropriate application once the port is open. The client would generate a random 16bit number to be the next sequence number. It encrypts that number and the requested port number to send to the server. For the key, it uses the existing sequence number and the pre-shared secret. It sends the packet, presently a SYN packet with the encrypted data as the payload, and listens for a response. The response at this time will be a RST packet to be able to make it past most firewalls (the client will allow for specifying the port if necessary to work around firewall restrictions). Once the ACK packet is received, the sequence number is updated in the configs and the associated program is launched. In the event that the SPA client is not successful, a re-sync packet would be sent to sync the sequence number of the server and the client. The re-sync packet would use the current date and time in UTC [10] and pre-shared key as the key for the encryption. The server would generate a new sequence number and reply with a RST that would have the new sequence number encrypted with the shared secret as the key. If the new sequence number was not used within a grace period, the server would not be updated in the configs and the initial sequence number would be valid again. [1] Port Knocking - Network Authentication Across Closed Ports - Martin Krzywinski http://www.samag.com/articles/2003/0306/ [2] Port Knocking http://search.yahoo.com/bin/search?p=port.knocking [3] Port Knocking http://www.portknocking.org/ [4] Port Knocking About Obscurity http://www.portknocking.org/view/about/obscurity [5] cd00r http://www.phenoelit.de/stuff/cd00rdescr.html [6] SAdoor http://cmn.listprojects.darklab.org/ [7] Security Through Obscurity http://www.catb.org/~esr/jargon/html/S/security-through-obscurity.html [8] nmap http://www.insecure.org/nmap/ [9] I have to admit I am still investigating this detail, as the exacts about how the other packages work are sketchy and it means sniffing and digging through source code. [10] Date/Time would be only to the minute, and would require that client and sever be using some form of NTP or other network time syncing. Not as reliable as prefered.