Skip to content →

Modern Wireless Tradecraft Pt III — Management Frame Access Control Lists (MFACLs)

This content was originally published on the SpecterOps blog. The original can be found here:

In Part II of this series, we described how improvements in wireless client security have put a dent in our ability to use Karma attacks against modern devices (see: We then discussed the MANA, Loud Mode MANA, and Known Beacons attacks, which can be used to overcome these improvements.

In this next section, we will discuss how to use Management Frame ACLs (MFACLs) in EAPHammer to exert granular probe-level control over the offensive techniques we have described in previous sections (see: We’ll also discuss how these attacks work at an algorithmic level, and provide insight into how using MFACLs affects EAPHammer’s runtime efficiency.

Management Frame ACLs (MFACLs)

Karma, mana, and known beacon attacks are inherently messy techniques that can easily cause all of the devices around you to connect to your rogue AP, regardless of whether the devices are within the scope of your current operation. Even evil twin attacks suffer from this problem under certain circumstances, such as when the rogue AP is given a commonly used ESSID.

This presents a twofold problem: not only is targeting arbitrary nearby devices inherently illegal, it’s also detrimental to your ability to do your job. For rogue AP attacks to be useful from an operator’s perspective, we need to be able to execute them with precision. This means means limiting their impact and visibility to our intended targets.

MFACL Algorithm

Management Frame Access Control Lists (MFACLs) are the solution to this problem. MFACLs are Access Control Lists (ACLs) that are checked by the access point prior to handling incoming probe request frames. They can be either SSID-based or MAC-based, and can be used in either whitelist or blacklist mode.

The following table lists the different type of MFACLs available, as well their effects when used:

It should be noted that MFACLs cannot be used to restrict beacon frames, so they will not prevent client devices from seeing or attempting to connect to your rogue AP if you’re executing any of the following techniques:

  • evil twin attack
  • loud MANA attack
  • known beacon attack

Using MAC-based MFACLs in EAPHammer

Hostapd has offered native support for MAC-based MFACLs since version 2.8, which was released in April 2019 [1][2]. This saved me an enormous amount of work when incorporating them into EAPHammer, since the only modifications I had to make to hostapd were the ones pertinent to adding wildcard support. Interestingly enough, Sensepost’s hostapd-mana has supported MAC-based MFACLs since 2016 and SSID-based MFACLs since 2017, long before the adoption of MFACLs in vanilla hostapd (definitely not the first time they’ve been ahead of the curve) [3][4].

MAC-based MFACLs can be passed to EAPHammer in the form of text files containing a single MAC address per line:

# example EAPHammer MFACL file78:f0:97:fc:b5:36

Notice the use of wildcards in the example above. You can substitute any octet with a wildcard symbol, which allows you to do neat things like ignoring probe requests from any device with a specific OUI. This helps greatly when dealing with devices that use MAC address randomization (although EAPHammer’s implementation is not a complete solution due to insufficiently robust MAC pattern matching and inability to fingerprint devices). It’s important to point out that this isn’t an entirely unique EAPHammer feature, since both hostapd-mana and airodump-ng have been doing something similar with bitmasks for years [5][6]. In fact, EAPHammer ends up translating the wildcards to bitmasks at runtime, so the underlying implementation ends up being pretty similar [7].

Once you’ve created your MFACL file, you can pass it to EAPHammer using either the ` — mac-whitelist` flag or the ` — mac-blacklist` flag:

# use MFACL whitelisting./eaphammer -i wlan0 --essid exampleCorp --cloaking full --karma --mac-whitelist /path/to/mac/whitelist/file.txt
# use MFACL blacklisting./eaphammer -i wlan0 --essid exampleCorp --cloaking full --karma --mac-blacklist /path/to/mac/blacklist/file.txt

Effect of MAC-based MFACLs on Runtime Efficiency

Since MAC-based MFACLs are a built-in feature of vanilla hostapd, they’re pretty heavily optimized. Vanilla hostapd accepts a list of MAC addresses as a configuration parameter, converts the individual MAC addresses to byte arrays, and stores the byte arrays in a sorted linked-list before the access point is initialized [8].

Once the access point is up and running, the ACL lookups are performed using a binary search [8]. This yields a worst-case runtime efficiency of O(log n), where n is the number of entries in the ACL. The comparisons are done using `os_memcmp`, which is one of the more heavily optimized comparison functions that Linux has to offer. With that said, using MFACLs may still slow your AP down, particularly in dense urban environments where spectrum congestion is an issue. Ironically, using MFACLs is especially important in environments like this, so my personal recommendation is to keep your MFACLs short to avoid long processing times.

The actual binary search code is located inthe `hostapd_maclist_found()` function within the `src/ap/ap_config.c` file of hostapd’s source code. It’s absolutely beautiful from a programmer’s perspective, and a rare opportunity to witness fundamental concepts of computer science used in a practical environment [8]:

912 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
913 const u8 *addr, struct vlan_description *vlan_id)
914 {
915 int start, end, middle, res;
917 start = 0;
918 end = num_entries - 1;
920 while (start <= end) {
921 middle = (start + end) / 2;
922 res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
923 if (res == 0) {
924 if (vlan_id)
925 *vlan_id = list[middle].vlan_id;
926 return 1;
927 }
928 if (res < 0)
929 start = middle + 1;
930 else
931 end = middle - 1;
932 }
934 return 0;
935 }

src/ap/ap_cconfig.c (source: hostapd 2.8) [8]

Unfortunately, you can’t actually do a simple binary search when wildcards are introduced into the mix. To deal with the wildcard issue, EAPHammer’s updated `hostapd_maclist_found()` function first checks for the presence of a flag that denotes whether a wildcard has been set. If the flag has been set to true, the function falls back to a linear search. Otherwise, the binary search is used. I tried to make the linear search as simple as possible, and made sure to leverage `os_memcpy()` and `os_memcmp()` whenever possible [9].

851     if ( eaphammer_global_conf.acl_has_wildcards ) {
853 // fall back to linear search if list contains wildcards
854 for (i = 0; i < num_entries; i++) {
857 // we need to use os_memcpy to copy addr into addr_cpy, since
858 // addr is a constant pointer
859 os_memcpy(addr_cpy, addr, ETH_ALEN);
861 // apply current entry's bitmask to addr_cpy
862 for (j = 0; j < ETH_ALEN; addr_cpy[j] &= list[i].mask[j++]);
864 res = os_memcmp(list[i].addr, addr_cpy, ETH_ALEN);
865 if (res == 0) {
866 if (vlan_id) {
867 *vlan_id = list[i].vlan_id;
868 }
869 return 1;
870 }
871 }
872 }
873 else {
875 // no wildcards? awesome - do the binary search
876 start = 0;
877 end = num_entries - 1;
879 while (start <= end) {
880 middle = (start + end) / 2;
881 res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
882 if (res == 0) {
883 if (vlan_id) {
884 *vlan_id = list[middle].vlan_id;
885 }
886 return 1;
887 }
888 if (res < 0) {
889 start = middle + 1;
890 }
891 else {
892 end = middle - 1;
893 }
894 }
895 }
897 return 0;
898 }

local/hostapd-eaphammer/src/ap/ap_config.c (source: eaphammer )[9]

This is an important thing to remember when using EAPHammer’s MAC-based MFACL functionality, since it has a direct impact on the tool’s runtime efficiency. When wildcards are used, the worst-case runtime efficiency of EAPHammer’s MAC address ACL lookup degrades from O(log n) to O(n), which is considerably slower. Once again, this shouldn’t make too much of a difference unless you’re in a highly populated environment and using an obsessively long ACL.

It’s probably possible to do a more efficient wildcard search using a different container structure and algorithm (directed acyclic word graphs come to mind). But as they say, premature optimization is the root of all evil. Until I start receiving issues on Github complaining of slow probe response times, and it’s clearly evident that the search algorithm isn’t the problem, I probably won’t bother unless I’m really bored.

Using ESSID-based MFACLs in EAPHammer

ESSID-based MFACLs are not currently a feature that exists in vanilla hostapd, but have existed in hostapd-mana since 2017 and in EAPHammer since October 2019 [4][10]. Like MAC-based MFACLs, ESSID-based MFACLs can be passed to EAPHammer in the form a text file with a single entry per line:

# example ESSID-based MFACL fileapples

EAPHammer does not currently support wildcards for its ESSID-based MFACLs, although this may change in the future depending on feasibility and user-demand.

It’s important to note that EAPHammer will allow you to use place whitespace at at the start and end of each line in the file, and interpret this whitespace as a part of the ESSID. In other words, make sure to proofread your SSID-based ACLs before using them in production (should I need to tell you this?).

Once you’ve created your MFACL file, you can pass it to EAPHammer using either the ` — ssid-whitelist` flag or the ` — ssid-blacklist` flag:

# use MFACL whitelisting./eaphammer -i wlan0 --essid hackresponsibly --cloaking full --karma --ssid-whitelist /path/to/mac/whitelist/file.txt# use MFACL blacklisting./eaphammer -i wlan0 --essid hackresponsibly --cloaking full --karma --ssid-blacklist /path/to/mac/blacklist/file.txt

Effect of SSID-based MFACLs on Runtime Efficiency

Your access point may take a performance hit when SSID-based MFACLs are used, and this performance hit may be more noticeable than the one experienced when using MAC-based MFACLs (due to string comparisons). As with MAC-based ACLs, this shouldn’t be a huge issue so long as your ACL isn’t unreasonably long. However, it’s still something to be aware of.


This concludes Part III of this writeup. We will conclude this series with Part IV, in which we will go over some basic tradecraft recommendations for offensive wireless practitioners, as well as some high level defensive recommendations for detecting rogue AP attacks.



Published in Wireless


Leave a Reply

Your email address will not be published. Required fields are marked *