Getting the better of sniffers
Today’s networks generally use switches rather than hubs to connect everyone together. Hubs radiate every packet to every connected computer, to cut down on processing power and price; each computer then filters out its own packets and discards the rest. Switches improve performance by sending only your packets to your computer, filtering out other network traffic automatically so you don’t see it at all. As a handy security side-effect, switches make network sniffing much harder. Sniffing is where you deliberately don’t filter out everyone else’s packets in order to snoop on who’s doing what, However, even in a switched network, you can still usually inject spoofed packets: Network traffic that is constructed to look as though it come from someone else on the same network.
Of course, you’ll be flying blind, because you’ll never see the replies: They’ll go to the other person instead. You might think, therefore, that a blind packet injection attack might allow an attacker to disrupt your network, but not to retrieve any information from it. But Linux bug CVE-2016-5696 reveals a way that an attacker can send out this sort of ‘blind’ packet and nevertheless extract details about what you are doing, without even seeing the reply that comes back. In particular, crooks can use CVE-2016-5696 to figure out which servers you are currently connected to, which is handy information in its own right for social engineers or spies. Once the crooks know that you have an open connection to a specific server, the researchers also showed that the crooks can probably go on to figure out how to inject a data packet that is accepted as legitimate, even though they’re flying blind. Of course, if crooks can sneak packets into your data flow undetected, they may be able to trick you into consuming malicious content, for example by injecting booby-trapped fields in web forms to phish for passwords, or by adding exploit code in file downloads to infect you with malware.
The CVE-2016-5696 problem, ironically, comes from a feature that was added to Linux to make network tampering harder, not easier. RFC 5961 is entitled ‘Improving TCP’s Robustness to Blind In-Window Attacks,’ and it’s supposed to stop an imposter on the network guessing enough about any individual TCP connection to mess with it deliberately through blind packet injection. Part of the solution is a special sort of packet called a Challenge ACK (ACK is short for acknowledgement) that one end of a connection sends out if it thinks someone is trying to mess with the connection. A Challenge ACK requires the other end to send a reply based on a secret number that a blind attacker doesn’t know, and almost certainly won’t be able to guess. Of course, this makes Challenge ACKs an important resource, so the Linux kernel developers introduced a mechanism to stop a blind attacker from deliberately injecting traffic to provoke Challenge ACKs simply to overload the system. Linux does this by restricting the maximum number of Challenge ACKs that the operating system will generate each second; this is set by default to 100, which is more than enough in most cases.
Planning to fail
Unfortunately, the Challenge ACK rate-limiting feature, offiically referred to by Linux asnet.ipv4.tcp_challenge_ack_limit, allows a crook to leak connectivity data. Assume that an attacker called M wants to answer the question, ‘Is user A connected to server B right now?’ (That’s not a huge leak of data, to be sure, but it’s very handy information for a cybercrook, and, anyway, the whole idea of RFC 5961 is to make it harder to leak that sort of data, not easier!)
- Inject a bogus packet from M that pretends that A is talking to B. If A and B really are connected, B will produce a Challenge ACK because M’s spoofed packet will look suspicious. (If there is no existing connection, no Challenge ACK will be generated.)
- Make a regular connection from M to B and deliberately trigger exactly 100 Challenge ACKs within the next second.
- Count how many Challenge ACKs come back to M.
You can see how this works: If the bogus packet (1) triggers a Challenge ACK (which will be invisible to M), then only 99 Challenge ACKs are left for the rest of the next second at stage (2). So, if all 100 Challenge ACKs come back from stage (2), then stage (1) had no effect, and thereforeA is not connected to B. But if only 99 Challenge ACKs show up, then one of the ACKs had already been eaten up, and so A is indeed connected to B. Data leakage!
What to do?
This is an interesting rather than a calamitous bug, for all that you may have seen headines saying that it could ‘disrupt Tor’ and ‘inject malware.’
Importantly, crooks can’t use this attack as a way of poisoning a specific website to attack anyone who visits it, as they could if they hacked into the site itself and altered its content directly.
Also, they can’t use this attack (at least in any practicable way that we can see) to strip away your anonymity on Tor, or to sniff your traffic.
Nevertheless, here are three things you can do:
- If you run a vulnerable Linux server, increase the number of Challenge ACKs allowed per second. For example, if you set the limit to one million Challenge ACKs a second (see below), or even higher, stage (2) of this attack will become impractical, so a crook will never be able to reach the limit to watch for the ‘one-of-them-went-missing’ telltale described above.
- If you run a web server, upgrade from HTTP from HTTPS. A blind injection attack that alters data in your network stream must know what to inject in advance, without seeing any data from the stream to help it decide. Blindly predicting what to inject into an HTTPS connection is impossible because the attacker doesn’t know how to encrypt it correctly.
- Wherever you have routers in your network, make sure that they reject spoofed network packets as far as possible. If a packet has a source IP number that would be impossible given the network interface on which it arrived, drop it. This will reduce the number of places from which bogus packets can be injected.
For the future, the researchers say that they will be proposing the following possible fixes to the Linux community:
- Keep a separate Challenge ACK counter for each connection, so that stage (3) above will always see 100 Challenge ACKs triggered by stage (2), and will therefore learn nothing from stage (1).
- Randomly and regularly modify the Challenge ACK limit up or down slightly, so that an attacker can’t predict the right count for stages (2) and (3).
This bug isn’t the end of the world as we know it, but it’s a fascinating lesson in how adding restrictions with the aim of improving security may paradoxically end up reducing it.