Use static ARP table entries to combat spoofing and other nefarious activities.
As discussed in “Detect ARP Spoofing” [Hack #62], a lot of bad things can happen if someone successfully poisons the ARP table of a machine on your network. The previous hack discussed how to monitor for this behavior, but how do you prevent the effects of someone attempting to poison an ARP table?
One way to prevent the ill effects of this behavior is to create static ARP table entries for all of the devices on your local network segment. When this is done, the kernel will ignore all ARP responses for the specific IP address used in the entry and use the specified MAC address instead.
You can create static entries with the arp
command, which allows you to directly manipulate the kernel’s ARP table entries. To add a single static ARP table entry, run this command:
#arp -s
ipaddr macaddr
For example, if you know that the MAC address that corresponds to 192.168.0.65 is 00:50:BA:85:85:CA
, you could add a static ARP entry for it like this:
# arp -s 192.168.0.65 00:50:ba:85:85:ca
For more than a few entries, this can be a time-consuming process. And for it to be fully effective, you must add an entry for each device on your network on every host that allows you to create static ARP table entries.
Luckily, most versions of the arp
command can take a file as input and use it to create static ARP table entries. Under Linux, this is done with the -f
command-line switch. So, all you need to do is generate a file containing the MAC and IP address pairings, which you can then copy to all the hosts on your network.
To make this easier, you can use this quick-and-dirty Perl script:
#!/usr/bin/perl # # gen_ethers.pl <from ip> <to ip> # my ($start_1, $start_2, $start_3, $start_4) = split(/\./, $ARGV[0], 4); my ($end_1, $end_2, $end_3, $end_4) = split(/\./, $ARGV[1], 4); my $ARP_CMD="/sbin/arp -n"; for(my $oct_1 = $start_1; $oct_1 <= $end_1 && $oct_1 <= 255; $oct_1++ ){ for(my $oct_2 = $start_2; $oct_2 <= $end_2 && $oct_2 <= 255; $oct_2++){ for(my $oct_3 = $start_3; $oct_3 <= $end_3 && $oct_3 <= 255; $oct_3++){ for(my $oct_4 = $start_4; $oct_4 <= $end_4 && $oct_4 < 255; $oct_4++){ system("ping -c 1 -W 1 $oct_1.$oct_2.$oct_3.$oct_4 > /dev/null 2>&1"); my $ether_addr = \Q$ARP_CMD $oct_1.$oct_2.$oct_3.$oct_4 | egrep 'HWaddress| (incomplete)' | awk '{print \$3}'\Q; chomp($ether_addr); if(length($ether_addr) == 17){ print("$ether_addr\t$oct_1.$oct_2.$oct_3.$oct_4\n"); } } } } }
This script will take a range of IP addresses and attempt to ping each one once. This will cause each active IP address to appear in the machine’s ARP table. After an IP address is pinged, the script will then look for that IP address in the ARP table and print out the MAC/IP address pair in a format suitable for putting into a file to load with the arp
command. (This script was written with Linux in mind, but it should work on other Unix-like operating systems as well.)
For example, if you want to generate a file for all the IP addresses ranging from 192.168.1.1 to 192.168.1.255 and store the results in /etc/ethers, run the script like this:
# ./gen_ethers 192.168.1.1 192.168.1.255 > /etc/ethers
When you run arp
with the -f
switch, it will automatically use the /etc/ethers file to create the static entries. However, you can specify any file you prefer. For example, to use /root/arp_entries instead, run this:
# arp -f /root/arp_entries
This script isn’t perfect, but it can save a lot of time when creating static ARP table entries for the hosts on your network. Once you’ve generated the file with the MAC/IP address pairings, you can copy it to the other hosts and add an arp
command to the system startup scripts, to automatically load them at boot time.
The main downside to using this method is that all the devices on your network need to be powered on when the script runs; otherwise, they will be missing from the list. In addition, if the machines on your network change frequently, you’ll have to regenerate and distribute the file often, which may be more trouble than it’s worth. However, this method can protect devices that never change their IP or MAC addresses from ARP poisoning attacks.