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:
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).
I found 2 ways of having wpa_supplicant
output the PMK:
wpa_supplicant
with the -K
option, together with some debug option (e.g. -dd
). This will include keys (passwords, etc.) in debug output.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] = {'\0'};
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) = '\0';
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Key negotiation completed with "MACSTR": \
\n\tPMK=%s \
\n\t[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.