How to Detect ARP Spoof Attack using Scapy in Python

Writing a simple Python script using Scapy that identifies and detects an ARP spoof attack in the network.
  · 4 min read · Updated may 2021 · Ethical Hacking · Packet Manipulation Using Scapy

In the previous tutorial, we have built an ARP spoof script using Scapy that once it is established correctly, any traffic meant for the target host will be sent to the attacker's host, now you are maybe wondering, how can we detect this kind of attacks ? well, that's what we are going to do in this tutorial.

The basic idea behind the script that we're going to build is to keep sniffing packets (passive monitoring or scanning) in the network, once an ARP packet is received, we analyze two components:

  • The source MAC address (that can be spoofed).
  • The real MAC address of the sender (we can easily get it by initiating an ARP request of the source IP address).

And then we compare the two. If they are not the same, then we are definitely under an ARP spoof attack!

Writing the Script

First let's import what we gonna need (you need to install Scapy first, head to this tutorial or the official Scapy documentation for installation):

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

Then we need a function that given an IP address, it makes an ARP request and retrieves the real MAC address the 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, the sniff() function that we gonna use, takes a callback (or function) to apply to each packet sniffed, let's define it:

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:
                # 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

Note: Scapy encodes the type of ARP packet in a field called "op" which stands for operation, by default the "op" is 1 or "who-has" which is an ARP request, and 2 or "is-at" is an ARP reply.

As you may see, the above function checks for ARP packets. More precisely, ARP replies, and then compares between the real MAC address and the response MAC address (that's sent in the packet itself).

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

sniff(store=False, prn=process)

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

When you try to run the script, nothing will happen obviously, but when an attacker tries to spoof your ARP cache like in the figure shown below:

ARP Spoof script gets executed

The ARP spoof detector (ran on another machine, obviously) will automatically respond:

The detector detects an ARP SpoofAlright that's it!

To prevent such man-in-the-middle attacks, you need to use Dynamic ARP Inspection, which is a security feature that automatically rejects malicious ARP packets we just detected.

Here are some further readings:

Check the full code.

Happy Crafting ♥

View Full Code
Sharing is caring!

Read Also

Comment panel