A Randomizing Wi-Fi MAC Address AP Hopper

by Eprom Jones

In response to RSG's article in 22:1 concerning the "hunting" of Wi-Fi Leeches, I offer this simple method of masking your Media Access Control (MAC) using Perl and Linux.

My example focuses on my own Slackware system, because that is what I have, but should work on nearly all UNIX and probably BSDs and OS X.  That means your laptop (very sorry, Microsoft).

The first identifiable trait of a computer on a network is its MAC address.  You can tell the vendor and sometimes model by looking up the octets.  If the vendor is vigilant in its record keeping, the MAC address is traceable to the person who purchased it.  Some people might want to avoid that, for whatever reason.

One reason is to see if you can do it.  I have an Intel 802.11B/G 2200 card built into my laptop and in the interest of a sort of superficial plausible deniability, I looked up the MAC addresses assigned to Intel at good 'ole coffer.com/mac_find.

Since they had a bunch, I copied nine of them:

00:AA:00
00:A0:C9
00:03:47
00:02:B3
00:0E:0C
00:04:23
00:12:F0
00:13:92
00:11:11

Note:  They all start with zeros.

So then all we need to create a plausible, yet random, MAC address is a simple Perl script to randomly select one of those nine prefixes, then fill in the rest of the hex digits.  Cake.

#!/usr/bin/perl
$one = "00";
@twos = ( "aa", "a0", "03", "02", "0e", "04", "12", "13", "11" );
@threes = ( "00", "c9", "47", "b3", "0c", "23", "f0", "02", "11" );
@news;

for ($i=0; $i<6; $i++)  {
    $temp = sprintf "%1x", rand(16);
    $news[$i] =$temp;
  }

$real_combo = rand(9);
$newMAC = sprintf ("%s:%s:%s:%s%s:%s%s:%s%s", $one, $twos[$real_combo], $threes[$real_combo], $news[0], $news[1], $news[2], $news[3], $news[4], $news[5]);
print "$newMAC\n";

This script makes a string Real:Intel:MAC:RandomRandom:RandomRandom:RandomRandom.  A nYCe RaNd0m MAC address.

In order to assign your new MAC address to your Wi-Fi adapter you can just add:

print `ifconfig eth0 hw ether $newMAC`;

to your script.

The eth0 is the name of my adapter.

Yours could be eth3, wlan0, en0, fxp0, etc.

The hw ether tells ifconfig that it's going to change a hardware address of type ether.

Before setting the MAC address, you need to have loaded your Wi-Fi card driver.

In order to prevent your card from automatically yelling out its name like a toddler trying to make friends, you need to load the wireless driver in non-associative mode.

For my card:

print `modprobe ipw2200 associate=0`;

For other chipsets, the command will be different.

The non-associative setting is not necessary.  It just feels cleaner to know your real MAC address was never broadcast at all.

So, putting these things together, here is a Perl script AP hopper that gets you online with a random MAC address:

#!/usr/bin/perl
#
# an ap hopper using random MAC by eprom.jones@gmail.com
#

use Term::ANSIColor qw(:constants);
#use HotKey;

sub doit
    {
     print GREEN, "\n Doin it... \n", RESET;
     print `iwconfig eth0 ap $mac[$use]`;
     print `iwconfig eth0 essid $essid[$use]`;
     print `iwconfig eth0 channel $chan[$use]`;
     sleep (1);
     system (`/sbin/dhcpcd -d -t 10 eth0`);
     print GREEN, "OK...\n", RESET;
    }

sub stopradio
    {
     print RED, "\n quitin' time. \n", RESET;
     system (`/sbin/dhcpcd -k`);
     system (`modprobe -r ipw2200`);
    }

sub startradio
    {
     system (`modprobe ipw2200 mode=0 channel=0 associate=0`);
     print   `ifconfig eth0 hw ether $newMAC`;
    }

$one = "00";      
@twos = ( "aa", "a0", "03", "02", "0e", "04", "12", "13", "11" );
@threes = ( "00", "c9", "47", "b3", "0c", "23", "f0", "02", "11" );
@news;
for ($i=0; $i<6; $i++)
  {	
    $temp = sprintf "%1x", rand(16);
    $news[$i] =$temp; 
  }
$real_combo = rand(9);
$newMAC = sprintf ("%s:%s:%s:%s%s:%s%s:%s%s", $one, $twos[$real_combo], $threes[$real_combo],
                                  $news[0], $news[1], $news[2], $news[3], $news[4], $news[5] );
print "$newMAC\n";

startradio;
system (`iwlist eth0 scan 1>/tmp/froglog.pad 2>/dev/null`);
open(INFILE,  "/tmp/froglog.pad")   or die "Can't hear no damned ribbits.";
while (<INFILE>)
  {
    if (/$\d{2}/)
      {
        s/ //g;
        /^(.*s:)(.*)$/;
        push @mac,$2;
      }
    if (/ESSID/)
      {
        s/ //g;
        /^(.*\")(.*)\"$/;
        push @essid,$2;
      }
    if (/$802\.11.+?/)
      {
        /^(.*802\.11)(.+?)$/;
        push @freq, $2;
      }
    if (/^.*Channel/)
      {
        /^(.*:)(.+?)$/;
        push @chan, $2;
      }
    if (/^.*Encryption/)
      {
        /^(.*:)(.+?)$/;
        push @crypt, $2;
      }
    $i++;
  }
close INFILE;

for ($ARGV[0] =~ /stop/)
  {
    stopradio;
    exit;
  }

for ($ARGV[0] =~ /start/)
  {
    startradio;
    print GREEN, "\n\t ]-]o   }={o   Pick a Number 1 thru ", $#mac+1,"   o}={  o[-[ \n", RESET;
    for ($c=0; $c le $#mac; $c++)
      {
        if ($crypt[$c] =~ /on/)
          {
            $l=$c+1;
            print "\n$l  ", RED, "$essid[$c]", RESET;
            next;
          }
        if ($freq[$c] !~ /g/)
          {
            $l=$c+1;
            print "\n$l  ", YELLOW, "$essid[$c]", RESET;
            next;
          }
        $l=$c+1;
        print "\n$l  ", GREEN, "$essid[$c]", RESET;
      }
    print "\n";

   $key = readkey();
   $use=$key-1;

   unless ($key !~ /[0-9+?]/ || $use>$#mac)
     {
       for ($#mac>0)
         {
           print GREEN, "\n You've chosen $essid[$use]", RESET;
           doit;
         }
       if ($#mac=0)
         {
           print RED, "\n\nSorry, bad scan. Please re-run.\n", RESET;
         }
     }

     if ($key !~ /[0-9+?]/ || $use>$#mac)
       {
         print RED, "hey \"visible\" NUMBERS only\n", RESET;
       }
     
     exit;
 }

Code: hopper.pl

Return to $2600 Index