BSSID randomization support

Just watched this video about tracking users through Apple’s WPS api: https://www.youtube.com/watch?v=hlbjUvkoyBA

A remedy for being able to track AP’s would be to randomize the bssid, f.e. on every device boot (or for ROS on every disable/enable?).

Is it correct that, besides scripting it yourself, this isn’t supported by RouterOS (yet)?

Here is a small/quick script that could be scheduled nightly to randomize the bssid of enabled wifi networks (not tested with capsman).

Script ensures that mac addresses are locally administered and follow Structured Local Address Plan (so first octet is X2)

:global createRandomMac do={
  :local mac ""
  :local sep ""

  :for n from=1 to=6 do={
    :local oct [:convert [:rndnum from=0 to=255] from=num to=hex]

    # Ensure first octet ends in 2 to follow SLAP
    :if ($n = 1) do={
      :local b1 [:pick "$oct" 0 1]
      :set oct ("$b1"."2")
    }

    :set mac "$mac$sep$oct"
    :set sep ":"
  }

  :return "$mac"
}

:foreach wifi in [/interface/wifi/find where disabled=no] do={
  :local name [/interface/wifi/get value-name=name number=$wifi]
  :local oldmac [/interface/wifi/get value-name=mac-address number=$wifi]
  :local newmac [$createRandomMac]
  :put "Changing mac-address for wifi network '$name' from $oldmac to $newmac"
  /interface/wifi/disable numbers=$wifi
  /interface/wifi/set mac-address=$newmac number=$wifi
  /interface/wifi/enable numbers=$wifi
}

Your version have from=num to=hex work only for v7.18 and up.

For work also on previous v7.1rc7 and up version using :rndstr is more easy.

Do not use for variables names already assigned to something.

Ignoring useless logging and useless frills, this suffice:

/interface/wifi
:foreach item in=[find] do={
    set $item mac-address="02$[:rndstr from="123456789ABCDE" length="10"]"
}

This assign random MAC addressses avoiding 0 and F for skip all particular circumstances.
289.254.654.976 possible values.

Curiosity:
However remote, there is always the possibility that different interfaces on different AP take the same value…
or that the random MAC is identical to the device that want to connect…

@rextended Awesome, thanks for optimizing. It’s clear that you really are a (Forum) Guru :slight_smile:

Here is my approach which I’m using (on ROS 7.16.2):

:local randBssid do={
  :local macOctets [:toarray ""]
  :local oct ""
  :for i from=0 to=[:len $bssid] do={
    :local chr [:pick $bssid $i ($i + 1)]
    :if ($chr = $macDelimiter) do={
      :set macOctets ($macOctets, $oct)
      :set oct ""
    } else={:set oct "$oct$chr"}
  }
  :set macOctets ($macOctets, $oct)
  :if ([:len $macOctets] != 6) do={
    :return ""
  }
  :foreach i in={1;2;3} do={
    :set ($macOctets->$i) [:rndstr from="123456789ABCDE" length=2]
  }
  :return [:serialize $macOctets delimiter=$macDelimiter to=dsv]
}

:global bssidRandomizerRunning

:if (!$bssidRandomizerRunning) do={
  :set bssidRandomizerRunning true

  :local bssids [:toarray ""]
  :local macDelimiter ":"
  :local maxIterations 100

  /interface/wifi
  :foreach i in=[find disabled=no] do={
    :local bssid [get $i mac-address]
    :local rBssid ""
    :local count 0
    :local found false
    :do {
        :set rBssid [$randBssid bssid=$bssid macDelimiter=$macDelimiter]
        :set count ($count + 1)
        :set found false
        :if ($rBssid != "") do={
          :foreach b in=$bssids do={
            :if (!$found && $b = $rBssid) do={:set found true}
          }
        }
    } while=($found && $count < $maxIterations)

    :if ($rBssid != "" && $count < $maxIterations) do={
      :set bssids ($bssids, $rBssid)
      set $i mac-address=$rBssid
    } else={
      :local ifName [get $i name]
      :if ($count = $maxIterations) do={
        :log warn "Unable to generate unique random MAC address (BSSID) for wifi interface '$ifName', max iterations reached (bug?), skipping..."
      } else={
        :log warn "Unable to parse MAC address (BSSID) '$bssid' set on wifi interface '$ifName', skipping..."
      }
    }
  }

  :set bssidRandomizerRunning
}

and yes, [$num2hex] can be raplaced with [:rndstr from=“123456789ABCDE” length=2]) as @rextended suggested above, will change that…

It randomizes 2-4 octets (:foreach i in={1;2;3} do={…) from current wifi mac address (BSSID) and ensures that all new generated macs are unique, last 2 octets I’m using for personal tracking, it can be easily changed which octets to randomize in mentioned :foreach loop.
Added 2 schedulers to execute this script, on startup (with 5s delay before script execution) and each day at night time.

Edit: updated script with [:rndstr …] to generate random octet.
Edit2: removed wifi enabled status toggle on bssid change

How about CAPsMAN? Schedule script on each CAP?

Not using CAPsMAN, but it think it is more complex than just set random mac on CAP device, I think script executed on CAP will need also to update new mac on CAPsMAN device, over API for eg. Also maybe better solution will be to run script on CAPsMAN which will randomize macs for each CAP client and update wifi mac on CAP over API, anyway different script needs to be made for CAPsMAN.

(Not tested on capsman) On interfaces is not needed at all to disable and enable the interface, is automatic when change anything on wifi (also comment…)

I’m disabling wifi interface to force clients to disconnect when bssid is changed, but I will check how client behaves when bssid is changed while connected…

Can confirm that @rextended’s script without disabling/enabling wifi works, but I’m not using it for capsman yet

FYI, I filed a feature request for adding CAPsMAN BSSID-randomization support: SUP-185072

@infabo how can I track status updates of the feature request SUP-185072?

@ma3yat https://help.mikrotik.com/servicedesk/servicedesk/customer/portal/1/SUP-185072

FYI

Hello,

Thank you for contacting MikroTik Support.

The feature request has been noted. That being said, it’s currently not planned to add this functionality, at least not in the near term.

Best regards,