cat posts/2017-10-24-krack-breaking-the-wpa2-four-way-handshake.md

KRACK: breaking the WPA2 four-way handshake

· 6 min read · security cryptography networking

A week ago yesterday, Mathy Vanhoef of KU Leuven published KRACK, short for key reinstallation attacks, and for a day or two the headlines said WPA2 was broken. That’s true, in an annoying, specific way, and the actual mechanism is one of the nicest protocol bugs I’ve read about in a while. AES is fine and your Wi-Fi password is safe. The bug is in the state machine of the handshake itself, so nearly every implementation that followed the standard correctly was affected, which is a strange sentence to write.

I spent a chunk of the weekend reading the paper (Vanhoef and Frank Piessens, to be presented at ACM CCS in Dallas next week), and this is my attempt at the explanation I wanted on Monday morning.

The four-way handshake

When your phone joins a WPA2 network, it and the access point already share a secret, the pairwise master key (PMK). For a home network that’s derived from the passphrase and the network name. For a corporate 802.1X network it comes out of the RADIUS exchange. Either way, the PMK is long-lived, so it isn’t used to encrypt traffic directly. Instead, every time you connect, the two sides run the four-way handshake to derive a fresh session key, the PTK, from the PMK plus two random numbers:

  1. The AP sends a random nonce, the ANonce.
  2. The client picks its own random SNonce, computes the PTK from the PMK, both nonces and both MAC addresses, and sends the SNonce back with a MIC (a message authentication code) so the AP knows it has the right PMK.
  3. The AP computes the same PTK, and sends message 3, which says “install the key” and also carries the group key used for broadcast traffic.
  4. The client installs the PTK and replies with message 4 to say it’s done.

From then on, every data frame is encrypted with the PTK using, usually, CCMP, which is AES in counter mode with a MAC. Each frame has a packet number that goes up by one every time, and that packet number is the nonce for the encryption.

Where it breaks

Wireless networks drop frames. So the standard says that if the AP doesn’t get message 4, it should resend message 3, and the client should accept a retransmitted message 3 even if it’s already installed the key. And when the client gets that retransmitted message 3, it installs the key again. Installing the key resets the packet number to zero.

That’s the whole bug. If an attacker can make the AP resend message 3, the client reinstalls the same key it’s already using and starts counting packet numbers from the beginning again, which means it reuses nonces it has already used with that key.

The attacker makes the AP resend message 3 by sitting in the middle and dropping message 4. Vanhoef does this with what he calls a channel-based man-in-the-middle: clone the real AP’s MAC address on a different Wi-Fi channel, get the client to connect through you, and forward the handshake frames between the two channels, except the ones you want to hold back. The handshake is still between the real client and the real AP. The attacker never learns the PMK and doesn’t need to, he only needs to be able to delay and replay frames.

client attacker (MitM) access point msg 1: ANonce msg 2: SNonce, MIC msg 3: install, group key install PTK, packet number = 0 msg 4 blocked data, packet number 1 no msg 4, so resend msg 3 reinstall PTK, packet number = 0 data, packet number 1 again same key, same nonce the attacker never learns the key, only replays and delays frames
The attack against the four-way handshake. Dropping message 4 makes the AP resend message 3, and the client resets its nonce when it reinstalls the key.

Why a reused nonce is so bad

Counter mode turns AES into a stream cipher. AES encrypts the key plus the nonce plus a counter to make a keystream, and the ciphertext is just the plaintext XORed with the keystream. Same key and same nonce means same keystream, every time. So if two frames are encrypted with the same keystream, XORing the two ciphertexts cancels the keystream completely, and you’re left with the XOR of the two plaintexts.

One byte, to make it concrete. Say the keystream byte is 0x3c, one frame has an H (0x48) at that position and the other has an a (0x61):

0x48 ^ 0x3c = 0x74      ciphertext 1
0x61 ^ 0x3c = 0x5d      ciphertext 2
0x74 ^ 0x5d = 0x29      = 0x48 ^ 0x61, the key is gone

If the attacker knows or can guess either plaintext, he gets the other one. And on a network a lot of plaintext is guessable: protocol headers, DHCP, ARP, the first bytes of an HTTP request. Once you know a plaintext and its ciphertext you know that stretch of keystream, and anything else encrypted with that nonce falls out. This is the two-time pad, a staple of CTF crypto challenges, and I’ve lost count of how many of those I’ve solved by XORing two ciphertexts and squinting at the result. It’s a bit startling to see it in a protocol that billions of devices use.

What an attacker can do depends on the cipher. With CCMP, which is what almost everyone uses, he can decrypt and replay frames, but not forge new ones. With the older TKIP or with GCMP, the paper shows he can also forge frames, which means injecting traffic, which is much worse. The reinstall also resets the replay counter, so old frames can be replayed back at the client.

Android and Linux get it worst

There’s one case where it’s far worse than nonce reuse. wpa_supplicant, the Wi-Fi client used by Linux and Android, clears the key from memory after it’s installed, which is a sensible thing to do with a key. From version 2.4, when the retransmitted message 3 arrives, it reinstalls what’s now in memory, which is an all-zero key. So the attacker doesn’t have to fiddle with keystreams at all. He knows the key: it’s zero. Everything that device sends can be decrypted and modified. Android 6.0 and later use the affected versions, and that’s a lot of phones that may not get updates quickly, or at all.

The demo video on the KRACK site does this to an Android phone, and combines it with sslstrip to get a login out of a site that wasn’t using HTTPS properly. That part’s worth emphasizing. TLS still works over a broken Wi-Fi link. If a site uses HTTPS everywhere with HSTS, KRACK gets the attacker encrypted traffic he can’t read. The sites that break are the ones that let the first request go over plain HTTP.

What I’ve done about it

The good news is that it’s fixable in a backward-compatible way, because the fix is just “don’t reinstall a key that’s already installed”, and a patched client still talks to an unpatched AP. Most of the attack is against the client side of the handshake, so patching clients matters more than patching routers, though APs that act as clients (repeaters, mesh nodes) and the fast BSS transition handshake used for roaming on corporate networks are also affected. Microsoft had already shipped a fix in the October 10th Patch Tuesday. Apple says it’s fixed in the current betas. The Linux hostapd and wpa_supplicant patches were out on disclosure day, and most distros had packages within a day or two. OpenBSD got a fix in early, with Vanhoef’s agreement, after they were notified over the summer, which caused some grumbling about embargoes.

At work our laptops are mostly Windows and macOS, so that was mostly a matter of checking that the October update was installed and nagging people about the macOS one when it ships. The office access points got a firmware update on Thursday. The harder question was phones, which we don’t manage, so I sent the team a short note saying which Android versions were affected, that the VPN is the right answer on any network you don’t control, and that HTTPS-only sites were fine either way.

For my own stuff, I spent part of Saturday checking the IoT junk on my home network, and I suspect half of it will never get a patch. That’s the part of this that won’t go away quickly, and it isn’t specific to KRACK. (The SHA-1 collision in March was the same problem in slow motion: the replacement had existed for twelve years, and the long tail of things still using SHA-1 was what got left behind.)