"To kill the Enemy, you should know him as well as you know yourself."—Anonymous
Not long ago, TCP hijacking was one of the most popular techniques for intruders to gain unauthorized access to Internet servers. Even now that almost every systems administrator knows about this potential vulnerability, TCP hijacking is still common because many systems administrators don't understand the principles behind this method. They just can’t stop wily hackers who know their stuff. To build an effective defense, you need to understand all of the details about TCP hijacking. That's why I suggest that you start with a brief review of the TCP protocol.
An overview of TCP
Transmission Control Protocol (TCP) is one of the basic protocols of the transport layer of the Internet. This protocol makes it possible to fix errors during packet transfers. It sets up a logical connection—a virtual link that we can assume is free from error. Low-level algorithms control the packet queue and request that damaged or incorrect packets be resent. TCP processes packets by sequence number as they are received, and it puts out-of-order packets back into place. All of this is transparent to the virtual link, which disappears when the connection session ends. The TCP protocol is the only protocol from the TCP/IP protocol family that has additional packet and connection identification and authentication mechanisms. That explains why application level protocols, such as SMTP, FTP, and Telnet, use TCP to gain remote access to other hosts.
For TCP packet identification, the TCP header consists of two 32-bit fields that are used as packet counters. They are named Sequence Number and Acknowledgment Number. Another field, named Control Bit, is 6 bits long, and it carries the following command bits:
- URG: Urgent pointer field significant
- ACK: Acknowledgment field significant
- PSH: Push function
- RST: Reset the connection
- SYN: Synchronize sequence numbers
- FIN: No more data from sender
Sample TCP connection setup scheme
Let's suppose that host A wants to set up a TCP connection with host B. In this case, host A sends host B a packet like this:
A -> B: SYN, ISSa
In the message that host A sent, command bit SYN is set, and Sequence Number has an initial sequence number ISSa that’s 32 bits long. After receiving this packet, host B generates a reply:
B -> A: SYN, ACK, ISSb, ACK (ISSa+1)
This reply sets the SYN and ACK command bits. Host B sets the Sequence Number to its initial sequence number ISSb, and the Acknowledgment Number is set to ISSa (from host A) and increased by 1. To finish the handshake, host A sends:
A -> B: ACK, ISSa+1, ACK (ISSb+1)
This packet sets ACK. The Sequence Number ISSa is increased by 1, and the Acknowledgment Number ISSb is increased by 1. After sending this packet to host B, host A ends the third-level handshake. A TCP connection between these hosts (A and B) is set up. From now on, host A can send data packets to host B through this new virtual TCP link:
A -> B: ACK, ISSa+1, ACK (ISSb+1); DATA
You can follow the entire TCP connection setup scheme in Figure A.
|This sample TCP connection setup scheme details the connection between host A and host B.|
How an intruder generates an attack
In the sample TCP connection setup scheme described above, the only identifiers of TCP clients and TCP connections are Sequence Number and Acknowledgment Number—two 32-bit fields. To generate a fake TCP packet, the only things that an intruder must know are the current identifiers for definite connection: ISSa and ISSb. The possibility of TCP packet substitution is becoming much more important because analysis of the FTP and Telnet protocols, which are based on the TCP protocol, shows that the problem of identifying FTP and Telnet packets is handled only by the transport layer protocol (TCP protocol) and nothing else. All an intruder has to do is get the current values of the identifiers of a TCP packet for a defined TCP connection (like a Telnet connection). Then, to have the intruder's packet recognized as valid, the intruder can send a packet from any Internet-connected host, as long as the packet is masked as a packet from any host that’s part of the connection (such as a TCP connection client host).
Neither FTP nor Telnet protocols check the source IP addresses of the hosts from which they receive packets. When these protocols get a fake packet from an attacker, they assume that it’s a valid one from the connected host and send a reply to the IP set in the fake packet. Then, the true connected host loses its connection because the counters in the reply don't match!
For an attack like the one depicted above to occur, the only pieces of information that an intruder is required to know are the two current 32-bit parameters (ISSa and ISSb) that identify the TCP connection. How can someone learn that information? When an attacker is in the same segment as the target or when the target's traffic comes through the attacker's segment, the task of getting ISSa and ISSb numbers becomes trivial. All the hacker must do is grab and analyze network traffic. The TCP protocol allows us to have secure connections only when the attacking side can’t grab (sniff) network traffic.
More difficult is the multi-segment attack—when the attacker and his target are located in different network segments. In these cases, the task of getting ISSa and ISSb numbers isn't so trivial. Hackers have two ways in which they can proceed: the first involves mathematically guessing the initial number of the TCP connection identifier by extrapolating its previous values, and the second involves using the habits of the identification process of the TCP connection parties for performing an rsh server attack.
Method 1: Guessing ISN values
How does the network operation algorithm form the initial ISSa number (the Initial Sequence Number, or ISN)? Obviously, from a security standpoint, the best answer would be to generate an ISN randomly through a software or hardware random number generator with a very large period. Thus, each new ISN wouldn't depend on a previous value; consequently, it wouldn't be even theoretically possible for an attacker to find a functional ISN generation dependence.
However, it appears that such obvious rules of ISN random generation weren't obvious to the TCP protocol description (RFC793) authors or to kernel developers of the different network operating systems. For example, the TCP protocol description recommends that the value of this 32-bit counter be increased by 1 every 4 microseconds. What do we see when this practice is implemented? Unfortunately, we see very poor results. In early Berkeley-compatible UNIX kernels, the value of this counter increased by 128 every second and by 64 with every new connection. Analysis of the Linux OS sources shows that the OS generates the ISN value not randomly, but as a dependent variable of the current time (where mcs equals time in microseconds, and s is the current time in seconds from the Epoch: 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time):
ISN = mcs + s * 1000000
Do you think that this problem disappears in other OSs? No! In the Windows NT 4.0 OS, the value of ISN increases 10 times about every millisecond (where ms is time in milliseconds):
ISN = ms * 10
More impressive is a Unix OS that’s certified to a B1 security level and that runs on a multiprocessing (SMP) high-uptime server and works as a fully functional firewall. It seems to be the most protected network OS, but it has a simple time-dependent ISN generation algorithm, too.
If the network operating system uses a time-dependent ISN generation algorithm, an attacker can guess the necessary function and close in on workable ISN values. As it comes from the practical OS explorations one can suggest a common form for the ISN generation function (where mcs equals time in microseconds—usually the shortest time period counted, depending on hardware—ms is time in milliseconds, and s is time in seconds):
ISN = F (mcs, ms, s)
You can shorten this formula to:
ISN = F (mÓs)
That's the common formula, and we can assume that the ISN generation function depends on microseconds. The function that’s most likely to be used will be a simple linear function.
When we've figured out which units of ISN measurement matter and what the functional dependencies are, we’re much closer to solving the problem of getting mcs arguments for the network operating system. First, you can try to analyze the sources of the operating system's kernel. Usually, you can’t because the OS kernel's sources aren't available. The exceptions include Linux and the three BSD variants, which come with open sources.
That's why the intruder will need to find another way of getting the relationship between ISN generation functional dependence and the mcs argument. Often, the intruder will use the network operating system as a "black box" and will implement a "request-answer" testing method. Many normal requests for TCP connection setup are sent to the victim network OS; after that, the intruder receives the same number of answers, with current ISN values in every moment of time. The intruder records the time periods of the answers in microseconds. As the result, the intruder will get a table of discrete ISN values and corresponding time values (where ISNn is an ISN that was received at time tn after the experiment started; the time when the experiment started is defined as 0):
ISN0 ISN1 ... ISNn
t0 t1 ... tn
Now, someone easily could use one of the known mathematical methods to derive the ISN function that depends on t:
ISN (t) = F (t), with time interval which varies from 0 to tn
This formula can get us another value of ISN from a previous value if we know the ISN generation function. Using this formula, an attacker can predict the next possible value of ISN, depending on the time interval.
The closer an attacker’s location is to the victim OS, the better the chance is that this attacker will get a valid function. The key is the time intervals. An attacker who is located far away from the victim OS will get much longer time intervals than a closer attacker and will have to account for variances in the packet transmission time. The attacker doesn't need to perform any experiments directly on the victim host. All the attacker needs to do is detect the type of OS that’s on the server. Then, the attacker can find a sample server with the same system and perform ISN function detection experiments on it.
Now for a few words concerning practical results taken from practical tests of the Linux and Windows NT 4.0 OSs. Here are the sample results that were received from the Linux OS during the definite time periods:
dISN 65135 134234 202324 270948 338028
t 2759 5685 8560 11462 14303
The graph in Figure B was based on the results from the table for the Linux OS. The graph demonstrates the particularly linear dependence of the ISN values:
|ISN values have a particularly linear dependence on time periods.|
After figuring out the ISN generation function in the operating systems on the server and client, the attacker will start to watch the server's OS and wait for the connection request from the client. When the connection is created, the attacker can count the possible range of ISN values that were used during the setup of the TCP link. Since the attacker can count ISN values only in the definite range (and even then, not exactly), the attacker can't avoid making guesses. If an attacker didn't perform the analysis that’s depicted above, however, the attacker would have to send 2^64 packets, which is unrealistic. Once the attacker has used the analytical techniques that I've described, the attacker has to send only about 100^2 packets to close in on the answer.
Method 2: Using the habits of the identification process to perform an rsh server attack
There's still another way in which an attacker can get ISSa and ISSb values: by using the habits of the identification process of the TCP connection parties to perform an rsh server attack. All UNIX-like OSs have concepts of a "trusted" host. Any host that can gain access to the server without an authorization and identification process is considered a trusted host. To access a server from a trusted host without an authorization process, you have to use remote service (r-service) protocols. Most UNIX-like OSs have rhosts files, which list the names and IP addresses of trusted hosts. Each program that’s part of the r-services (such as rlogin and rsh) uses this file to determine whether a host is trusted or not. The only identification parameter of the trusted host is the IP address. (Almost every program from r-services uses TCP protocol as a basic protocol.)
One of the r-services programs is the remote shell program (rsh). It gives an attacker the possibility of gaining unauthorized access to a host. rsh gives any trusted host the opportunity to send any command to a shell on the victim server. What’s important in this case is that it's enough just to send a request and never to get a reply. For an attacker, the biggest problem in the r-service attack is that the attacker needs to send a packet from the name of a trusted host; the source IP address field should have the IP address of a trusted host. Obviously, the reply would be sent directly to the trusted host and never to the attacker's host.
R.T. Morris was the first person to describe this remote attack scheme. Let's examine the details of such an attack, which is diagramed in Figure C.
Host A is supposed to be a trusted host for host B. Host C is the attacker's host. Host C opens a real TCP connection with host B to its TCP ports (mail, echo, etc). As a result, host C gets the current value of ISNb. Mimicking host A, host C sends a TCP connection request to host B:
C (A) -> B: SYN, ISSx
When host B receives this request, it analyzes the IP address of the source host and thinks that this packet came directly from host A. Of course, host B sends the new value of ISNb’ to host A as a reply:
B -> A: SYN, ACK, ISNb', ACK (ISSx+1)
Host C would never get this packet from host B. Using the previous value of ISNb’ and the attacker's scheme for getting ISNb’, however, host C can send a new packet to host B:
C (A) -> B: ACK, ISSx+1, ACK (ISNb'+1)
To send this packet, host C would have to try several possible values of ACK (ISSb'+1) but would never need to try ISSx+1 values because host C has already received this parameter of the TCP connection from host B in the first packet.
If such an attack is possible, the attacker is ready for the next problem. When host C (using the name of host A) sends the packet to host B, host B will reply to host A. Since host A never sent any packets to host B, however, host A will send a packet with the RST bit set to host B. It’s a request to host B to close the connection. Of course, this request doesn’t suit the attacker (host C). Host C needs to blast host A with a Denial of Service (DoS) attack to prevent it from responding to host B.
As a result, the rsh server on host B supposes that it has a connection with the user of trusted host A; in reality, it’s the attacker from host C. The attacker from host C will never get replies from host B but can still execute commands (r-commands) on host B.
|Host C attacks the r-service by pretending to be trusted host A.|
The technique of TCP hijacking is rather old. After Kevin Mitnick, the famous hacker, used it in 1995 to gain access to Tsutomu Shimomura's workstation and the details of this event were published, TCP hijacking became a very powerful weapon for hackers. To implement such an attack, a hacker must be a highly qualified specialist. However, the biggest developers of operating systems have found different ways to defend against this attack strategy—or at least to design some workarounds.
Supposedly, this technique is rarely used anymore. Still, I would say that even nowadays about 35 percent of Internet-connected servers are still vulnerable to this kind of an attack. The main problem isn't the weakness of the OS (though this problem still exists); rather, the problem is trusted hosts and trusted services, such as rsh, rlogin, and rcmd.
An OS upgrade won’t save a systems administrator from headaches caused by a hacker's attacks. All too often, one attack leads to others, and at least one will hit the target. The solution is to build a defendable security system that’s based not on the tremendous variance of passwords between different servers, but on the principles of service distribution and access control by physical and administrative methods. So, be safe and take care.
Alexander Prohorenko is a student of computer sciences. For the last three years, he worked as a leading system administrator and coder for one of the largest ISPs in Ukraine, and he installed and integrated much of the Internet infrastructure for that country. Now he’s engaged in quality systems programming and high performance web coding for Network Lynx, an American company that’s based in Rio Rancho, NM.
Donald Wilde owns Silver Lynx, a control electronics development specialty company. He’s also a technical partner in Network Lynx, a Web-based virtual company that uses the best of open-source tools for Internet business. Don has been interested in computing since 1980, when he learned to program his first computer, a 16-bit Intel SDK-86, in raw machine code. Don especially likes to build code that "makes the machines dance." He would be willing to compare quality code to any other art form, and he believes that software design is a marriage of creative artistic flow and discipline.The authors and editors have taken care in preparation of the content contained herein, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.