Apple Private Wi-Fi Addresses

 · 10 mins read

TL;DR: This post briefly explains how iOS implements MAC address randomization in iOS 14 and what it means for your examination. Pro tip: use iLEAPP, but I’m sure you already do.


I upgraded one of my test devices to iOS 14 when it came out to give a quick rundown of what changes occurred in Apple Notes and how they would impact a forensic examination. Strangely, my device claimed it lacked Internet after the upgrade. Upon digging in, it became apparent that the MAC address I was expecting for that device was not the MAC address it was providing, which is a problem when you allow access to a test network for only specific devices.

“Private Address”

What caused my issue was the fact that Apple was now defaulting to using “private Wi-Fi addresses” in iOS 14. This did not appear anywhere in the list of “All New Features” on the iOS 14 website, but there was some buzz about it for those that follow iOS news. As I am woefully behind on iOS news, I learned about it when I hit Settings->Wi-Fi->[My SSID], saw that “Private Address” was checked to “Yes”, and noted that the different MAC address my router was complaining about was being displayed on my phone. Once I turned that setting off, my expected MAC address was back and I got network access again.

To be clear about the term “Private Address”, this is Apple’s term for MAC address randomization. MAC address randomization is just a systematic way of doing what many of us have done for decades: talking to your network using a different MAC address than what is actually burned onto your network card. In this case, Apple gave out a link-local MAC address which is not guaranteed to be globally unique, in an OUI which was not reserved for Apple. With “private addresses”, Apple provides a different MAC address for each network you connect to in hopes of protecting your privacy. I say “in hopes of” because I generally find it comical for a company to implement a “turn off Wi-Fi button” which helpfully says “turning off Wi-Fi until tomorrow” and then force “private addresses” by default. Or for the same company in the same iOS release to openly say they’ll bounce the pictures you have tagged on your phone against your security cameras and tell you who they think is at the door1. Or for the same company to accidentally tell you all networking is turned off when it clearly isn’t2.

True privacy considerations aside, many manufacturers can support MAC address randomization and this has been used when your phone reaches out to see if Wi-Fi networks are around for a long time. It is worth noting that this is supported in other operating systems and the difference now in iOS 14 is defaulting the behavior on, using it not just for network probes, and having a somewhat static MAC address for each different network.

What does this mean for you? It means that if you were looking at network monitoring data from three different locations your suspect was at, you might not be able to prove their presence until you get their phone because the MAC address on all three networks would be different, and not anything registered to the suspect.

iOS “Private Addresses”

In iOS 14, your phone needs to remember the MAC address it has chosen for that network until you choose to forget the network. If your phone needs to remember it, then we can recover it, but first we have to find it. To do this, I took a dump of my phone and then went with good old Forza Bruta, grepping for my SSID.

[notta@cuppa itunes-backup]$ grep -r OneAppleParkWay
Binary file ad/ade0340f576ee14793c607073bd7e8e409af07a8 matches
Binary file 0f/0fa75546343ba224c9fe55adc73e8fdedc1029c3 matches
Binary file 47/47001e38c986d26ed52f64f1a3aeda98813e561f matches
Binary file 82/8218978e4ab0a48035bb92653145a6be872ea858 matches
Binary file e3/e36b35ae4cc6038f9ce83b5e097f216144278b17 matches
Binary file c9/c99767746f00337b3cd26396f22e104963efe2a0 matches

Six matches were more than I expected and after running them through Manifest.db, I was able to see what they were:

SELECT fileID, relativePath 
FROM Files 
WHERE fileID in ('ade0340f576ee14793c607073bd7e8e409af07a8', 
File ID Relative Path
47001e38c986d26ed52f64f1a3aeda98813e561f SystemConfiguration/
8218978e4ab0a48035bb92653145a6be872ea858 SystemConfiguration/preferences.plist
ade0340f576ee14793c607073bd7e8e409af07a8 SystemConfiguration/
c99767746f00337b3cd26396f22e104963efe2a0 Library/Preferences/
e36b35ae4cc6038f9ce83b5e097f216144278b17 SystemConfiguration/

Some of these should be well known to you already, but SystemConfiguration/ was new to me and happens to have no results on Duck Duck Go. Let’s see what is inside!

[notta@cuppa itunes-backup]$ file e3/e36b35ae4cc6038f9ce83b5e097f216144278b17
e3/e36b35ae4cc6038f9ce83b5e097f216144278b17: Apple binary property list

[notta@cuppa itunes-backup]$ ruby ~/ruby/bplister/plist_parse.rb \

{"List of scanned networks with private mac"=>
  [{"MacGenerationTimeStamp"=>2020-09-28 19:52:38 111837/2097152 -0400,
    "lastJoined"=>2020-10-20 10:26:24 1753825/2097152 -0400,
    "FirstJoinWithNewMacTimestamp"=>2020-09-28 19:58:23 240149/524288 -0400,
     2020-10-20 06:52:46 3661321/4194304 -0400,
    "lastUpdated"=>2020-10-20 10:27:30 848537/4194304 -0400,
    "addedAt"=>2019-12-03 20:31:31 353971/1048576 -0500,

The above output looks similar to the file, it includes the network SSID and BSSID, for example. However, it also has the PRIVATE_MAC_ADDRESS section which holds the really relevant information for the phone to know which MAC address was associating with this SSID. In this case, you can see that PRIVATE_MAC_ADDRESS_VALID is false and the PRIVATE_MAC_ADDRESS_IN_USE is my real MAC address3 because I had this feature turned off at the time I dumped the phone, but we can still learn a lot.

Don’t believe me? Convert the values that look like “garbage” into their hex form and add some colons to them:

def hexify_byte(byte_to_convert):
  to_return = hex(byte_to_convert).replace('0x','')
  if len(to_return) < 2:
    to_return = "0" + to_return

  return to_return

def bytes_to_mac_address(encoded_bytes):
  to_return = ''
  to_return = hexify_byte(encoded_bytes[0]) + ":" + hexify_byte(encoded_bytes[1]) + ":"
  to_return = to_return + hexify_byte(encoded_bytes[2]) + ":" + hexify_byte(encoded_bytes[3]) + ":"
  to_return = to_return + hexify_byte(encoded_bytes[4]) + ":" + hexify_byte(encoded_bytes[5])

  return to_return

real_mac = bytes_to_mac_address(b'@\x9C(\x0B\x9A\x51')
private_mac = bytes_to_mac_address(b'\x86\x16P\x42\x90\\')
print(f'Real MAC: {real_mac}\nPrivate MAC: {private_mac}')

# Real MAC: 40:9c:28:0b:9a:51 (note: this is a real Apple OUI)
# Private MAC: 86:16:50:42:90:5c (note: this is a link-local MAC not within an Apple OUI)

Apple changes the computed MAC only when you forget the network and re-add it. This means that, whether the user has “Private Address” turned on for that network at that time or not, you know the private address they would have used if they did. If you have an iPhone in evidence and needed to prove whether or not it had connected to the networks you suspect them of connecting to, you could do that with network logs from the networks in question and this file, as long as they didn’t bother forgetting the network4.


I hacked together a quick parsing of this file to pull out the private MAC addresses and add them to iLEAPP’s output. This builds on the existing Wi-Fi parsing, but adds a report named “WiFi Networks Scanned (private).” It can pull this information from either SystemConfiguration/ or SystemConfiguration/ although the latter is more current on my iOS 14.0.1 device.

It will spit out something that looks like the below. You will want too pay attention to the “MAC Used For Network” field (this is what is currently being used on that network) and the “Private MAC Computed for Network” field (this is what would be used if “Private Addresses” was turned on for that network). I believe the “MAC Valid” field will help you understand if “Private Addresses” is turned on.

Output of Wifi Networks Scanned (private) plugin


When it comes to the impact of MAC address randomization, regardless of operating system, on your investigations, be very aware that it is a thing and it is being pushed more aggressively by more manufacturers as time goes on. You cannot rely on any one fact to make a decision about whether a given device was or was not in a given place, use all the information you have. In the case of iOS specifically, take a peek at SystemConfiguration/ if you have it, it may add some important information to your understanding.


  1. “In addition to person, animal, and vehicle detection, security cameras can identify people you’ve tagged in the Photos app for richer activity notifications.” iOS Release Features 

  2. That happened and is still occuring

  3. Because I do believe in privacy, I’ve changed the MAC address to be a comperable one. 

  4. Although in the spirit of “trust but verify”, it would be worth seeing what it takes to make this truly disappear. Apple says forgetting the network is enough, we might want to prove that. In the iOS 14 Beta these rolled every 24 hours and that caused quite a stir among network operators, so I wouldn’t be shocked if the pendulum swung really far the other way.