Skip to content
Advertisement

Extracting the PMK from a WiFi client under EAP-PEAP authentication, for analysis on Wireshark

I’m starting a research project related to WiFi, which requires me to analyze the exchange of frames in between a WiFi client and AP during connection setup.

Experimental setup: I have a laptop M, capturing WiFi traffic with Wireshark on monitor mode, a device A (running Linux) connecting to a WiFi network via 802.1x authentication, specifically using the EAP-PEAP protocol.

I only control the laptop M and device A, but not the APs nor the network (which includes the RADIUS servers).

Objective: I’d like to decode the WiFi data frames captured by Wireshark on laptop M. According to this Wireshark how to, I would need to somehow extract the PMK (Pairwise Master Key) exchanged between the network and device A.

Since I only control device A, I would need to extract the PMK from it.

Problem: I don’t know how to extract that PMK from device A (assuming a Linux operating system), specially considering we’re talking about a EAP-PEAP session, and I haven’t been able to find any conclusive hints while searching on the Web.

I could find this discussion, which implies the PMK is stored directly at the WiFi NIC or the driver.

Questions:

  • Is it even possible to extract the PMKs, e.g. in a Linux system, without a major modification on the client system (e.g. modifying the code of the wireless drivers, etc.)? I would imagine that to be very hard, given how serious such a ‘security breach’ would be.
  • Are the PMKs stored in some way (e.g. in Linux)? Following from the above, I would not expect that to be the case.
  • What code would I need to modify (let’s assume a Linux operating system) to extract the PMKs?

P.S.: I’d like to note that I don’t consider this to be a ‘hacking’ question (and thus not at odds with the policies of stackoverflow.com), since I control the client device (not only the monitoring device).

Advertisement

Answer

I found 2 ways of having wpa_supplicant output the PMK:

  1. Easy way: Call wpa_supplicant with the -K option, together with some debug option (e.g. -dd). This will include keys (passwords, etc.) in debug output.
  2. Hard way: Alter the code of wpa_supplicant to output keys. Given that the -K option exists, this way is unnecessarily hard, but it was the first thing I tried (don’t ask). I’ve summarized how I’ve done this below, which may be interesting for someone wishing to alter the code of wpa_supplicant.

2) Hard Way: Altering wpa_supplicant Code

I was able to find an answer by altering the code of wpa_supplicant, making it output the PMK during authentication. In my case, the client device was a Raspberry Pi model B+, V1 2, running Raspbian GNU/Linux 7 (wheezy), which used an old version of wpa_supplicant, namely v1.0, 2012-05-10.

For anyone wondering, I’ve altered the source file src/rsn_supp/wpa.c, function wpa_supplicant_key_neg_complete(), to output the PMK, as follows:

static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
                    const u8 *addr, int secure)
{
    // pass the pmk (pairwise master key) to a hex string.
    int i;
    // hex str to hold pmk. 1024 bit 
    // should be enough (the pmk is supposed to be 256 bit, thus 32 byte, thus 
    // 64 hex chars)
    char pmk_str[1024] = {''};
    char * pmk_ptr = pmk_str;
    // use os_snprintf() (as used by other methods in wpa.c)
    for (i = 0; i < sm->pmk_len; i++) {
        // wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
        //  "WPA: pmk[%d]: %02X", i, sm->pmk[i]);
        pmk_ptr += sprintf(pmk_ptr, "%02X", sm->pmk[i]);
    }
    *(pmk_ptr + 1) = '';

    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
        "WPA: Key negotiation completed with "MACSTR": 
        ntPMK=%s 
        nt[PTK=%s GTK=%s]", 
        MAC2STR(addr),
        pmk_str,
        wpa_cipher_txt(sm->pairwise_cipher),
        wpa_cipher_txt(sm->group_cipher));
(...)

}

This customization is available on my github.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement