MAC Randomization
This post is about MAC Addresses and dissecting their common randomization format.
- What is a MAC Address
- Governance and Definition
- Representation of a MAC Address
- Universal MAC Addresses
- MAC Randomization
- Local MAC Addresses
- Structure of Local MAC Addresses
- Detection Using Python
- Changelog
What is a MAC Address
A MAC address1 is an identifier for a network interface. This is sometimes referred to as a layer 2 address2 or physical address.
Note some networked devices may have multiple interfaces. This means a device could be identified by multiple MAC addresses.
There are different types of MAC addresses. Some are universally unique. Some are locally assigned (not universally unique). Some kinds have different lengths.
This post will only cover at the surface unicast 48-bit MAC addresses (with a 24-bit OUI), Universally Administered (UAA), and Locally Administered (LAA).
Governance and Definition
There are two standards bodies involved in MAC Addresses. The concept and definition is a recognized international standard.
The International Organization for Standardization (ISO) body defines MAC Address definition and representation. ISO legitimizes the format internationally. The original standard is ISO/IEC 10039 published first in 1991, but I was unable to find an available copy to review for this post.
The Institute of Electrical and Electronics Engineers (IEEE) is the authority, assigner, and maintainer of unique identifiers.
Representation of a MAC Address
A binary3 representation of a 48-bit MAC address is 6 octets of binary digits (bits):
octet | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
01110000 | 10000001 | 11101011 | 11001010 | 10101001 | 10110001 |
The human readable format of a 48-bit MAC address is represented by 12 hexadecimal (hex) characters. There are 16 characters in a single hex digit which represent values 0 to 9
and a to f
. This means hex is known as a base 16 numerical system. Each octet is represented by 2 hexadecimal characters.
A 48-bit MAC address represented in hexadecimal:
70:81:eb:ca:a9:b1
You might see hexadecimal representation in a few different formats. Here are some common ones:
-
70:81:eb:ca:a9:b1
- colon delimiter -
70-81-eb-ca-a9-b1
- hyphen delimiter -
7081.ebca.a9b1
- dot delimiter in groups of 4 hex digits -
7081ebcaa9b1
- no delimiter
Stacked binary and hexadecimal representation:
octet | 0 | 1 | 2 | 3 | 4 | 5 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
hex | 7 | 0 | 8 | 1 | e | b | c | a | a | 9 | b | 1 |
binary | 0111 | 0000 | 1000 | 0001 | 1110 | 1011 | 1100 | 1010 | 1010 | 1001 | 1011 | 0001 |
Universal MAC Addresses
Companies like Apple, Google, Microsoft, etc. request and purchase blocks of identifiers (MAC addresses) from the IEEE. The IEEE will assign them a 24-bit Organizationally Unique Identifier (OUI). The remaining bits are assigned however the company wishes given uniqueness is maintained.
When a network interface is using the MAC address assigned by the company, this is known as the burned-in address. This particular identifier is known as a Universal MAC Address.
Example representation of an OUI:
octet | 0 | 1 | 2 | |||
---|---|---|---|---|---|---|
24-bit OUI | ||||||
hex | 7 | 0 | 8 | 1 | e | b |
binary | 0111 | 0000 | 1000 | 0001 | 1110 | 1011 |
70:81:eb
is an OUI assigned to Apple by the IEEE. You can see for yourself by plugging in the hex representation into an OUI lookup tool4.
MAC Randomization
MAC randomization is not a new concept. It has been used for years by certain clients to randomize the address sent in probe requests. When associated, the client would send the real MAC address.
Many client manufacturers now enable MAC randomization by default. For both the probe request and association. This includes iOS 14, Android 10, and Windows 10. Jim Palmer has a great article on this.
This means the MAC randomization feature changes the burned-in address to a randomized MAC address. The idea of MAC randomization is to help protect end users from tracking or profiling across Wi-Fi networks. It is a privacy feature for consumers.
The common private MAC address format leveraged is technically known as the Locally Administered Address (LAA) format.
Local MAC Addresses
MAC address can either be universally or locally assigned. We already covered that universal addresses are assigned by the manufacturer. A locally administered address is not assigned from an IEEE block of MAC addresses.
We can determine whether a MAC address is universal or local by looking at a specific bit in the first octet. The distinguishment is by setting the second least significant bit (LSB) of the first octet.
If the second LSB is set (1
), the address is administered locally. If the second LSB is unset (0
), the address is administered universally:
-
0
: intended to be globally unique (OUI enforced) -
1
: locally administered
For a local example, the first octet of d6:70:b6:a2:b8:8a
contains d6
(2 hex digits). The binary representation of the first octet is 11010110
. Where bits 7-4 = 1101
or hex digit d
, and then bits 3-0 = 0110
or hex digit 6
. The second LSB is set. This is a local MAC address.
The second LSB is 1. It’s bit position 1 in the table below (the value two from the far right).
bit position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | |
MSB | LSB |
For a universal example, the first octet of 70:81:eb:ca:a9:b1
contains 70
(2 hex digits). The binary representation of the first octet is 01110000
. Where bits 7-4 = 0111
or hex digit 7
, and then bits 3-0 = 0000
or hex digit 0
. The second LSB is unset. This is a universal MAC address.
The second LSB is 0. It is represented by bit position 1 in the table below.
bit position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | |
MSB | LSB |
Structure of Local MAC Addresses
We can now look at the 2nd LSB of the first octet of a MAC address to determine if it is following the MAC randomization format.
Here are the possible unicast values for the 2nd digit of a MAC address:
bit position | 7-4 | 3 | 2 | 1 | 0 | hex | type |
---|---|---|---|---|---|---|---|
.... | 0 | 0 | 0 | 0 | x0 | universal | |
.... | 0 | 1 | 0 | 0 | x4 | universal | |
.... | 1 | 0 | 0 | 0 | x8 | universal | |
.... | 1 | 1 | 0 | 0 | xC | universal | |
.... | 0 | 0 | 1 | 0 | x2 | local | |
.... | 0 | 1 | 1 | 0 | x6 | local | |
.... | 1 | 0 | 1 | 0 | xA | local | |
.... | 1 | 1 | 1 | 0 | xE | local | |
MSB | LSB |
This means we can look at the second character of a MAC address for 2
, 6
, a
, or e
to determine if it is a randomized MAC:
x2:xx:xx:xx:xx:xx
x6:xx:xx:xx:xx:xx
xA:xx:xx:xx:xx:xx
xE:xx:xx:xx:xx:xx
Detection Using Python
Example Function
Here is an example using a Python function to test if a string representation of a MAC is a randomized MAC:
def is_randomized(mac: str) -> bool:
return any(local == mac[1].lower() for local in ["2", "6", "a", "e"])
Example:
>>> def is_randomized(mac: str) -> bool:
... return any(local == mac[1].lower() for local in ["2", "6", "a", "e"])
...
>>>
>>> macs = [
... "9a:38:2b:54:f3:7b",
... "b2:fd:70:62:b0:d9",
... "16:08:61:6f:a4:97",
... "5e:b8:22:43:61:6b",
... "00:0b:86:a3:71:22",
... "fc:ec:da:16:50:fb",
... "d4:20:b0:09:1c:bf",
... "a8:8e:24:a3:38:bc",
... ]
>>>
>>> for mac in macs:
... print(f"mac: {mac}, random? {is_randomized(mac)}")
...
mac: 9a:38:2b:54:f3:7b, random? True
mac: b2:fd:70:62:b0:d9, random? True
mac: 16:08:61:6f:a4:97, random? True
mac: 5e:b8:22:43:61:6b, random? True
mac: 00:0b:86:a3:71:22, random? False
mac: fc:ec:da:16:50:fb, random? False
mac: d4:20:b0:09:1c:bf, random? False
mac: a8:8e:24:a3:38:bc, random? False
Example Regular Expression
Here is a Python example using a regular expression to do the same thing:
>>> macs = [
... "9a:38:2b:54:f3:7b",
... "b2:fd:70:62:b0:d9",
... "16:08:61:6f:a4:97",
... "5e:b8:22:43:61:6b",
... "00:0b:86:a3:71:22",
... "fc:ec:da:16:50:fb",
... "d4:20:b0:09:1c:bf",
... "a8:8e:24:a3:38:bc",
... ]
>>>
>>> import re
>>>
>>> for mac in macs:
... match = re.search("^.[ae26].*", mac.lower())
... if match:
... print(mac)
...
9a:38:2b:54:f3:7b
b2:fd:70:62:b0:d9
16:08:61:6f:a4:97
5e:b8:22:43:61:6b
Changelog
- 2020/10/03: clarifications, add link to a post by Jim Palmer
Thanks to Keith Miller for reading drafts of this.
-
The Wikipedia MAC address article is a good reference for more in depth reading. The IEEE tutorial on Standard Group MAC Addresses is also essential. ↩
-
When referring to bit order in networks we use
network byte order
orbig-endian byte order
. This means the most significant bit is first. See endianness for the gory details. ↩ -
I use the Wireshark OUI lookup tool. ↩