Detecting ARP Spoofing Attacks Using Scapy in Python

How Does Python Detect ARP Spoofing Attacks? This article uses Scapy to write a simple Python script to identify and detect ARP spoofing attacks in your network.

In the previous tutorial, we used Scapy to build an ARP spoofing script, and once it’s established correctly, any traffic directed to the targeted host will be sent to the attacker’s host, and now you might be wondering, how do we detect this attack? Well, that’s what we’re going to do in this tutorial.

How to Use Scapy to Detect ARP Spoofing Attacks? The basic idea behind the script that we’re going to build is to constantly sniff packets in the network (passive monitoring or scanning), and once the ARP packets are received, we’ll analyze two components:

  • Source MAC address (can be spoofed).
  • The real MAC address of the sender (we can easily get it by sending an ARP request to the origin IP address).

Then we compare the two. If they’re not the same, then we’re definitely under an ARP spoofing attack!

Python Detection of ARP Spoofing Attack: Writing a Script

How Does Python Detect ARP Spoofing Attacks? First, let’s import what we need (you need to install Scapy first, go to this tutorial or the official Scapy documentation to install it):

from scapy.all import Ether, ARP, srp, sniff, conf

Then we need a function, given an IP address, which makes an ARP request and retrieves the real MAC address of that IP address:

def get_mac(ip):
    """
    Returns the MAC address of `ip`, if it is unable to find it
    for some reason, throws `IndexError`
    """
    p = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(pdst=ip)
    result = srp(p, timeout=3, verbose=False)[0]
    return result[0][1].hwsrc

After that, we will use the sniff() function to accept a callback (or function) to be applied to each sniffed packet, let’s define it, Python detects ARP spoofing attack sample code as follows:

def process(packet):
    # if the packet is an ARP packet
    if packet.haslayer(ARP):
        # if it is an ARP response (ARP reply)
        if packet[ARP].op == 2:
            try:
                # get the real MAC address of the sender
                real_mac = get_mac(packet[ARP].psrc)
                # get the MAC address from the packet sent to us
                response_mac = packet[ARP].hwsrc
                # if they're different, definitely there is an attack
                if real_mac != response_mac:
                    print(f"[!] You are under attack, REAL-MAC: {real_mac.upper()}, FAKE-MAC: {response_mac.upper()}")
            except IndexError:
                # unable to find the real mac
                # may be a fake IP or firewall is blocking packets
                pass

Note: Scapy encodes the type of the ARP packet in a field named “op”, which represents the action, by default, “op” is 1 or “who-has”, which is an ARP request, and 2 or “is-at” is an ARP reply.

How to Use Scapy to Detect ARP Spoofing Attacks? As you can see, the above function inspects the ARP packets. More precisely, the ARP reply is then compared to the actual MAC address and the response MAC address (sent in the packet itself).

All we need to do now is call the sniff() function with the callback written above:

sniff(store=False, prn=process)

Note: store=False tells the sniff() function to drop sniffed packets instead of storing them in memory, which is useful when the script is running for a long time.

How Does Python Detect ARP Spoofing Attacks? When you try to run the script, obviously nothing happens, but when an attacker tries to spoof your ARP cache, as shown in the following image:

The ARP spoofing detector (apparently running on another machine) automatically responds:

Okay, that’s it!

To prevent this type of man-in-the-middle attack, you’ll need to use dynamic ARP detection, which is a security feature that automatically rejects malicious ARP packets that we’ve just detected.