LWN.net Logo

Inferring TCP sequence numbers

By Jake Edge
January 3, 2013

Over the past few years, seemingly harmless internal kernel state that is available to user space has allowed attackers to gain useful information to facilitate their attacks. The TCP DelayedACKLost counter (exported to user space via the /proc/net/netstat virtual file) is yet another. It can be used to determine the sequence number of a TCP connection, which can lead to packet injection or connection hijacking.

TCP sequence numbers have proven to be problematic over the years. Sequence numbers essentially count the number of octets transferred in each direction in a TCP connection. Knowing the sequence number, along with IP address and port number, allows an attacker to interfere with a connection by spoofing (or faking) packets that appear to have come from the other endpoint. Endpoints will reject packets that contain invalid sequence numbers, so those numbers must be known to an attacker. Originally, sequence numbers were easily predicted, so, in the mid-1990s, RFC 1948 specified that the initial sequence number (ISN) for each side of a TCP connection should be randomized.

Randomization should make sequence numbers difficult for attackers to guess, but various ways to infer the sequence numbers for a connection have come about over the years. In this case, researchers Zhiyun Qian, Z. Morley Mao, and Yinglian Xie discovered a way to quickly determine the sequence number for an open connection using the DelayedACKLost counter as a side channel. The researchers presented a paper [PDF] with their findings at the ACM Conference on Computer and Communications Security back in October. In addition, Qian posted a summary of the problem to the kernel netdev mailing list in December:

The vulnerability would allow [a] local malicious program to gain write access to TCP connections of other applications. An example attack scenario (on android) would be "an attacker uploads a seemingly benign app to the google play, when run at the background, it can inject malicious HTML payload into a webpage open by the browser".

The problem is caused by the common TCP stats counters (the specific counter I found is DelayedACKLost) maintained by the kernel (but exposed to user space). By reading and reporting such counters to an external attacker (colluded), the aforementioned attack can be accomplished.

As described in their paper, the researchers found a way to use the DelayedACKLost counter as a reliable side channel to quickly narrow in on the sequence number. By having a client-side application relay the counter value to a collaborating host, which can then send probe packets to the client, a binary or N-way search can be done to determine the sequence number. In their test cases, the researchers were able to infer the sequence number using four to five round trips between the client application and its collaborator, which could complete in as little as 50ms.

The key to this search is a bug in the way the Linux kernel handles packets with incorrect sequence numbers. If a packet is received that has a sequence number "less than" that which is expected, the DelayedACKLost counter is incremented—regardless of whether the packet is an acknowledgment (ACK) or not. The calculation that is done to determine whether the number is less than what is expected essentially partitions the 32-bit sequence number space into two halves. Because DelayedACKLost does not get incremented if the sequence number is larger than the expected number, it can be used in a search to narrow in on the value of interest.

DelayedACKLost was once used to decide if the network stack should use delayed ACKs or not. It is meant to count missing incoming delayed ACKs. In normal usage, it is rarely incremented, so an attacker can get a "clean" signal by simply sending packets with various sequence numbers and observing their effects on the counter. The paper describes using an N-way search technique that splits the sequence number space into a small number of equal-sized bins, sends a different number of packets with sequence numbers from each bin, and uses the value of the counter to find the sequence number with fewer round trips between the client and the probing host.

Beyond just inferring sequence numbers, though, the paper lays out a number of ways to use that information to interfere with real connections. The first of those is to inject data into an existing connection. By using the inferred sequence number, the "off-path" (i.e. not a man in the middle) attacker can spoof a packet to the client. The example used is an HTTP response from some internet server. If that server takes "long enough" to respond, the sequence number can be determined and a fake response can be sent before the real server responds. That turns out to be the pattern for Facebook, for example, and the researchers were able to inject JavaScript into a client session to update the user's status. In addition, if an HTTP connection is used for multiple requests, later responses (after the sequence number has been determined) can be spoofed.

A similar technique, using the same counter, can determine the client-side sequence number. That number can be used by an attacker to send spoofed packets in the other direction, so client requests to the server can be faked.

Beyond that, two types of connection hijacking are possible. A passive hijacking can be done on kernels older than 3.0.2 because there were only 24 bits of randomness in the ISN. When the connection is established to the remote server, the off-path attacker immediately sends spoofed "reset" (RST) packets to the server with sequence numbers covering the entire 24-bit client ISN space. It then commences to determine the server's ISN using the DelayedACKLost counter and sends a spoofed response once it has done so.

For more recent kernels, there is still an active hijacking that can be performed by pre-calculating the client ISNs for a range of port numbers. By "port jamming" the other ports (i.e. using those port numbers so they aren't available), the malware can ensure that the outgoing connection originates from a known, pre-calculated port. ISNs change at a known rate, so the attacker can calculate the ISN based on what it originally determined and how much time has passed since the determination was made. The trick is to know that a connection will be made to the server "soon". Ensuring that is the "active" piece of the puzzle.

Both hijacking techniques require that the server have some kind of stateful firewall that discards "out of state" packets. Otherwise, RST responses from the server on a connection it thinks is closed will confuse the real client (which thinks the connection is still open). It turns out that many internet services (e.g. Facebook, Twitter) do have such firewalls.

All of the techniques described in the paper were put to use in fairly "real world" scenarios. An Android application was used on the client side to monitor the counter, while other servers acted as the off-path collaborator. Many Android devices are based on 2.6.x, so they are vulnerable to either of the two hijacking techniques. Beyond the Facebook-status-updating malware mentioned above, they were able to create ways to "phish" for Facebook credentials using connection hijacking.

The fix for the problem on Linux is to check that the ACK bit is set on the packet before deciding that it is a lost delayed ACK. Attackers cannot just switch to turning on the ACK bit on the probes, because they would need the sequence number in the other direction to use as the "ACK number" in the packet. Eric Dumazet has posted a patch to discard the packets that would trigger this bug, but there is more needed. The longer-term fix will require moving most of the packet safety checks to an earlier point in packet handling. That way, fewer kinds of bogus packets will get far enough into the networking stack to cause this kind of observable state change.

One other possible solution would be to remove access to the DelayedACKLost counter for non-privileged programs. That would likely be difficult to do in Linux, as it has become part of the kernel's ABI, but it is something to consider for the future. In their paper, the researchers pointed that out:

(1) Even though OS statistics are aggregated and seemingly harmless, they can leak critical internal network/system state through unexpected interactions from the on-device malware and the off-path attacker. Similar observations have been made recently in a few other studies as well, e.g., using procfs as side channels. Our study reveals specifically that the packet counters can leak TCP sequence numbers. (2). Our systems today still have too much shared state: the active TCP connection list shared among all apps (through netstat or procfs); the IP address of the malware's connection and other apps'; the global packet counters. Future system and network design should carefully evaluate what information an adversary can obtain through these shared state.

There certainly are dangers from exposing internal kernel state to user space—sometimes those dangers don't manifest themselves for quite some time. Doing so has its benefits, though, for users and developers. It is a bit of a tricky balancing act—one that is made more difficult by the "no ABI changes" policy in the kernel. In this case, though, it seems that a solution has been found without changing the ABI. While the examples given in the paper may seem somewhat trivial, the techniques could certainly be used in ways that are far more damaging than an embarrassing Facebook status update.


(Log in to post comments)

Inferring TCP sequence numbers

Posted Jan 4, 2013 12:28 UTC (Fri) by spender (subscriber, #23067) [Link]

Two things:

1) grsecurity has restricted /proc/net since 2001 or so and avoided the associated problems with these counters.
2) Why have I not seen any CVEs for this or the patches this summer associated with similar attacks?

-Brad

Does it affect TLS/SSL connections?

Posted Jan 4, 2013 18:41 UTC (Fri) by scripter (subscriber, #2654) [Link]

Is it possible to meaningfully inject packets for applications that use TLS/SSL?

Does it affect TLS/SSL connections?

Posted Jan 4, 2013 21:54 UTC (Fri) by zlynx (subscriber, #2285) [Link]

It shouldn't be possible because the encryption won't match up. However it could be used to abort the connections with corrupt data or FIN packets.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds