From edb7a3b748ad2d0a4b183c1904295213d6197def Mon Sep 17 00:00:00 2001 From: RISCi_ATOM Date: Mon, 20 Aug 2018 12:32:33 -0400 Subject: [PATCH] wpa_supplicant: fix CVE-2018-14526 Unauthenticated EAPOL-Key decryption in wpa_supplicant Published: August 8, 2018 Identifiers: - CVE-2018-14526 Latest version available from: https://w1.fi/security/2018-1/ Vulnerability A vulnerability was found in how wpa_supplicant processes EAPOL-Key frames. It is possible for an attacker to modify the frame in a way that makes wpa_supplicant decrypt the Key Data field without requiring a valid MIC value in the frame, i.e., without the frame being authenticated. This has a potential issue in the case where WPA2/RSN style of EAPOL-Key construction is used with TKIP negotiated as the pairwise cipher. It should be noted that WPA2 is not supposed to be used with TKIP as the pairwise cipher. Instead, CCMP is expected to be used and with that pairwise cipher, this vulnerability is not applicable in practice. When TKIP is negotiated as the pairwise cipher, the EAPOL-Key Key Data field is encrypted using RC4. This vulnerability allows unauthenticated EAPOL-Key frames to be processed and due to the RC4 design, this makes it possible for an attacker to modify the plaintext version of the Key Data field with bitwise XOR operations without knowing the contents. This can be used to cause a denial of service attack by modifying GTK/IGTK on the station (without the attacker learning any of the keys) which would prevent the station from accepting received group-addressed frames. Furthermore, this might be abused by making wpa_supplicant act as a decryption oracle to try to recover some of the Key Data payload (GTK/IGTK) to get knowledge of the group encryption keys. Full recovery of the group encryption keys requires multiple attempts (128 connection attempts per octet) and each attempt results in disconnection due to a failure to complete the 4-way handshake. These failures can result in the AP/network getting disabled temporarily or even permanently (requiring user action to re-enable) which may make it impractical to perform the attack to recover the keys before the AP has already changes the group keys. By default, wpa_supplicant is enforcing at minimum a ten second wait time between each failed connection attempt, i.e., over 20 minutes waiting to recover each octet while hostapd AP implementation uses 10 minute default for GTK rekeying when using TKIP. With such timing behavior, practical attack would need large number of impacted stations to be trying to connect to the same AP to be able to recover sufficient information from the GTK to be able to determine the key before it gets changed. Vulnerable versions/configurations All wpa_supplicant versions. Acknowledgments Thanks to Mathy Vanhoef of the imec-DistriNet research group of KU Leuven for discovering and reporting this issue. Possible mitigation steps - Remove TKIP as an allowed pairwise cipher in RSN/WPA2 networks. This can be done also on the AP side. - Merge the following commits to wpa_supplicant and rebuild: WPA: Ignore unauthenticated encrypted EAPOL-Key data This patch is available from https://w1.fi/security/2018-1/ - Update to wpa_supplicant v2.7 or newer, once available Pulled from upstream commit : b3983323a1f25c936ddfcc129c454b282e90eeed --- .../network/services/hostapd/files/hostapd.sh | 16 ++--- ...thenticated-encrypted-EAPOL-Key-data.patch | 43 ++++++++++++ .../patches/340-reload_freq_change.patch | 29 +++++++- .../patches/463-add-mcast_rate-to-11s.patch | 68 +++++++++++++++++++ .../hostapd/patches/600-ubus_support.patch | 10 +-- 5 files changed, 151 insertions(+), 15 deletions(-) create mode 100644 package/network/services/hostapd/patches/0001-WPA-Ignore-unauthenticated-encrypted-EAPOL-Key-data.patch create mode 100644 package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index e3fc0366d5..1f28661117 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -154,6 +154,7 @@ hostapd_common_add_bss_config() { config_add_string acct_server config_add_string acct_secret config_add_int acct_port + config_add_int acct_interval config_add_string dae_client config_add_string dae_secret @@ -211,8 +212,8 @@ hostapd_set_bss_options() { wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 wps_ap_setup_locked \ wps_independent wps_device_type wps_device_name wps_manufacturer wps_pin \ macfilter ssid wmm uapsd hidden short_preamble rsn_preauth \ - iapp_interface eapol_version acct_server acct_secret acct_port \ - dynamic_vlan ieee80211w + iapp_interface eapol_version dynamic_vlan ieee80211w nasid \ + acct_server acct_secret acct_port acct_interval set_default isolate 0 set_default maxassoc 0 @@ -252,11 +253,14 @@ hostapd_set_bss_options() { [ -n "$wpa_master_rekey" ] && append bss_conf "wpa_gmk_rekey=$wpa_master_rekey" "$N" } + [ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N" [ -n "$acct_server" ] && { append bss_conf "acct_server_addr=$acct_server" "$N" append bss_conf "acct_server_port=$acct_port" "$N" [ -n "$acct_secret" ] && \ append bss_conf "acct_server_shared_secret=$acct_secret" "$N" + [ -n "$acct_interval" ] && \ + append bss_conf "radius_acct_interim_interval=$acct_interval" "$N" } local vlan_possible="" @@ -377,9 +381,8 @@ hostapd_set_bss_options() { } if [ "$wpa" -ge "1" ]; then - json_get_vars nasid ieee80211r + json_get_vars ieee80211r set_default ieee80211r 0 - [ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N" if [ "$ieee80211r" -gt "0" ]; then json_get_vars mobility_domain r0_key_lifetime r1_key_holder \ @@ -720,6 +723,7 @@ wpa_supplicant_add_network() { } local beacon_int brates mrate [ -n "$bssid" ] && append network_data "bssid=$bssid" "$N$T" + [ -n "$beacon_int" ] && append network_data "beacon_int=$beacon_int" "$N$T" local bssid_blacklist bssid_whitelist json_get_values bssid_blacklist bssid_blacklist @@ -742,10 +746,6 @@ wpa_supplicant_add_network() { append network_data "mcast_rate=$mc_rate" "$N$T" } - local ht_str - [[ "$_w_mode" = adhoc ]] || ibss_htmode= - [ -n "$ibss_htmode" ] && append network_data "htmode=$ibss_htmode" "$N$T" - cat >> "$_config" < +Date: Sun, 15 Jul 2018 01:25:53 +0200 +Subject: [PATCH] WPA: Ignore unauthenticated encrypted EAPOL-Key data + +Ignore unauthenticated encrypted EAPOL-Key data in supplicant +processing. When using WPA2, these are frames that have the Encrypted +flag set, but not the MIC flag. + +When using WPA2, EAPOL-Key frames that had the Encrypted flag set but +not the MIC flag, had their data field decrypted without first verifying +the MIC. In case the data field was encrypted using RC4 (i.e., when +negotiating TKIP as the pairwise cipher), this meant that +unauthenticated but decrypted data would then be processed. An adversary +could abuse this as a decryption oracle to recover sensitive information +in the data field of EAPOL-Key messages (e.g., the group key). +(CVE-2018-14526) + +Signed-off-by: Mathy Vanhoef +--- + src/rsn_supp/wpa.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/src/rsn_supp/wpa.c ++++ b/src/rsn_supp/wpa.c +@@ -2157,6 +2157,17 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, c + + if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) && + (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) { ++ /* ++ * Only decrypt the Key Data field if the frame's authenticity ++ * was verified. When using AES-SIV (FILS), the MIC flag is not ++ * set, so this check should only be performed if mic_len != 0 ++ * which is the case in this code branch. ++ */ ++ if (!(key_info & WPA_KEY_INFO_MIC)) { ++ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, ++ "WPA: Ignore EAPOL-Key with encrypted but unauthenticated data"); ++ goto out; ++ } + if (wpa_supplicant_decrypt_key_data(sm, key, mic_len, + ver, key_data, + &key_data_len)) diff --git a/package/network/services/hostapd/patches/340-reload_freq_change.patch b/package/network/services/hostapd/patches/340-reload_freq_change.patch index 086ade9ced..0dcd7c913e 100644 --- a/package/network/services/hostapd/patches/340-reload_freq_change.patch +++ b/package/network/services/hostapd/patches/340-reload_freq_change.patch @@ -1,6 +1,6 @@ --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -80,6 +80,16 @@ static void hostapd_reload_bss(struct ho +@@ -80,6 +80,25 @@ static void hostapd_reload_bss(struct ho #endif /* CONFIG_NO_RADIUS */ ssid = &hapd->conf->ssid; @@ -13,14 +13,39 @@ + hapd->iconf->vht_oper_chwidth, + hapd->iconf->vht_oper_centr_freq_seg0_idx, + hapd->iconf->vht_oper_centr_freq_seg1_idx); ++ ++ if (hapd->iface->current_mode) { ++ if (hostapd_prepare_rates(hapd->iface, hapd->iface->current_mode)) { ++ wpa_printf(MSG_ERROR, "Failed to prepare rates table."); ++ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_WARNING, ++ "Failed to prepare rates table."); ++ } ++ } + if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next && ssid->wpa_passphrase_set && ssid->wpa_passphrase) { /* -@@ -179,21 +189,12 @@ int hostapd_reload_config(struct hostapd +@@ -158,6 +177,7 @@ int hostapd_reload_config(struct hostapd + struct hostapd_data *hapd = iface->bss[0]; + struct hostapd_config *newconf, *oldconf; + size_t j; ++ int i; + + if (iface->config_fname == NULL) { + /* Only in-memory config in use - assume it has been updated */ +@@ -179,21 +199,20 @@ int hostapd_reload_config(struct hostapd oldconf = hapd->iconf; iface->conf = newconf; ++ for (i = 0; i < iface->num_hw_features; i++) { ++ struct hostapd_hw_modes *mode = &iface->hw_features[i]; ++ if (mode->mode == iface->conf->hw_mode) { ++ iface->current_mode = mode; ++ break; ++ } ++ } ++ + if (iface->conf->channel) + iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel); + diff --git a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch new file mode 100644 index 0000000000..da146ba55e --- /dev/null +++ b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch @@ -0,0 +1,68 @@ +From: Sven Eckelmann +Date: Thu, 11 May 2017 08:21:45 +0200 +Subject: [PATCH] set mcast_rate in mesh mode + +The wpa_supplicant code for IBSS allows to set the mcast rate. It is +recommended to increase this value from 1 or 6 Mbit/s to something higher +when using a mesh protocol on top which uses the multicast packet loss as +indicator for the link quality. + +This setting was unfortunately not applied for mesh mode. But it would be +beneficial when wpa_supplicant would behave similar to IBSS mode and set +this argument during mesh join like authsae already does. At least it is +helpful for companies/projects which are currently switching to 802.11s +(without mesh_fwding and with mesh_ttl set to 1) as replacement for IBSS +because newer drivers seem to support 802.11s but not IBSS anymore. + +Signed-off-by: Sven Eckelmann +Tested-by: Simon Wunderlich + +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -1426,6 +1426,7 @@ struct wpa_driver_mesh_join_params { + #define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004 + #define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008 + unsigned int flags; ++ int mcast_rate; + }; + + /** +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -8997,6 +8997,18 @@ static int nl80211_put_mesh_id(struct nl + } + + ++static int nl80211_put_mcast_rate(struct nl_msg *msg, int mcast_rate) ++{ ++ if (mcast_rate > 0) { ++ wpa_printf(MSG_DEBUG, " * mcast_rate=%.1f", ++ (double)mcast_rate / 10); ++ return nla_put_u32(msg, NL80211_ATTR_MCAST_RATE, mcast_rate); ++ } ++ ++ return 0; ++} ++ ++ + static int nl80211_put_mesh_config(struct nl_msg *msg, + struct wpa_driver_mesh_bss_params *params) + { +@@ -9055,6 +9067,7 @@ static int nl80211_join_mesh(struct i802 + nl80211_put_basic_rates(msg, params->basic_rates) || + nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) || + nl80211_put_beacon_int(msg, params->beacon_int) || ++ nl80211_put_mcast_rate(msg, params->mcast_rate) || + nl80211_put_dtim_period(msg, params->dtim_period)) + goto fail; + +--- a/wpa_supplicant/mesh.c ++++ b/wpa_supplicant/mesh.c +@@ -379,6 +379,7 @@ int wpa_supplicant_join_mesh(struct wpa_ + os_memset(¶ms, 0, sizeof(params)); + params.meshid = ssid->ssid; + params.meshid_len = ssid->ssid_len; ++ params.mcast_rate = ssid->mcast_rate; + ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq); + wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled; + wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled; diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 0d9aca9aa2..dd962b47a6 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -41,7 +41,7 @@ HAPD_IFACE_DISABLED, --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -284,6 +284,7 @@ static void hostapd_free_hapd_data(struc +@@ -302,6 +302,7 @@ static void hostapd_free_hapd_data(struc hapd->started = 0; wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); @@ -49,7 +49,7 @@ iapp_deinit(hapd->iapp); hapd->iapp = NULL; accounting_deinit(hapd); -@@ -1142,6 +1143,8 @@ static int hostapd_setup_bss(struct host +@@ -1160,6 +1161,8 @@ static int hostapd_setup_bss(struct host if (hapd->driver && hapd->driver->set_operstate) hapd->driver->set_operstate(hapd->drv_priv, 1); @@ -58,7 +58,7 @@ return 0; } -@@ -1665,6 +1668,7 @@ static int hostapd_setup_interface_compl +@@ -1683,6 +1686,7 @@ static int hostapd_setup_interface_compl if (err) goto fail; @@ -66,7 +66,7 @@ wpa_printf(MSG_DEBUG, "Completing interface initialization"); if (iface->conf->channel) { #ifdef NEED_AP_MLME -@@ -1844,6 +1848,7 @@ dfs_offload: +@@ -1862,6 +1866,7 @@ dfs_offload: fail: wpa_printf(MSG_ERROR, "Interface initialization failed"); @@ -74,7 +74,7 @@ hostapd_set_state(iface, HAPD_IFACE_DISABLED); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); #ifdef CONFIG_FST -@@ -2292,6 +2297,7 @@ void hostapd_interface_deinit_free(struc +@@ -2310,6 +2315,7 @@ void hostapd_interface_deinit_free(struc (unsigned int) iface->conf->num_bss); driver = iface->bss[0]->driver; drv_priv = iface->bss[0]->drv_priv; -- 2.25.1