Home Blog What is DNS Rebinding? Exploitations and Security Best Practices

What is DNS Rebinding? Exploitations and Security Best Practices

What is DNS Rebinding? Exploitations and Security Best Practices

By registering a domain they control, an attacker can manipulate the DNS responses received by a client. They can thus bypass poorly implemented security controls as part of what is known as a DNS rebinding attack. The issue arises when a client validates an IP address for security purposes but then accesses the resource via a different address, for example following a new DNS resolution.

In this article, we explain how DNS rebinding works and outline various scenarios in which this technique can be used to gain unauthorised access to internal systems. We also detail the key security measures that can be taken to protect against it.

What is DNS Rebinding?

DNS rebinding exploits the fact that a domain is not permanently associated with an IP address. The same domain may legitimately resolve to different IP addresses over time, depending on the DNS responses received.

This property becomes problematic when a system checks the IP address associated with a domain before authorising a request, but then reuses that domain to establish the connection. An attacker controlling the domain can then manipulate the DNS response between these two stages: the domain may first point to an authorised public IP address, then to a private IP address, a loopback address or another sensitive target.

The connection is then established to a resource that the control mechanism was specifically designed to protect.

Exploiting Two Resolutions of the Same Domain

Operating principle

When a server verifies a user-provided domain by resolving it once and then later reuses the same domain name to fetch content, it can create a time-of-check to time-of-use (TOCTOU) window that DNS rebinding exploits.

At the time of the check, the server asks DNS for the domain’s address and gets a harmless public IP, so the validation logic concludes the destination is safe.

At the time of use, the server performs the actual HTTP request using the hostname again, and that second step typically triggers a fresh DNS resolution (either because the HTTP client resolves on connect, because a different server performs the fetch, or simply because of retry and redirect logic).

If the attacker controls the domain’s DNS, they can return a different answer on the second lookup, often by using a very low TTL, so the hostname that was “approved” a moment earlier now points to a private, loopback, or otherwise sensitive internal address.

Exploitation via an SSRF (Server-Side Request Forgery) attack

DNS rebinding is often used alongside SSRF because both techniques aim to make a server initiate requests to unintended targets. SSRF occurs when an application fetches a remote resource (URL) based on attacker-controlled input, and the attacker manages to influence the destination of that server-side request.

For example, a vulnerable server might resolve a user-supplied hostname to validate it. Once the hostname is deemed safe, the application reuses the same domain to fetch content. During the fetch, the server may resolve the hostname again and receive a different IP address than the one it validated, bypassing the security check.

app.get("/fetch", async (req, res) => {
  try {
    const url = new URL(req.query.url || "");

    // TRUNCATED: Verify the URL scheme (HTTP or HTTPS)

                // First resolution to verify the IP address of the provided hostname
    const { address } = await dns.lookup(url.hostname);

    if (isPrivateIp(address)) res.sendStatus(403);

                // Second resolution to fetch content
    const r = await fetch(url, { redirect: "manual" });

    res.send(await r.text());
  } catch {
    res.sendStatus(500);
  }
});
Code snippet: Express GET /fetch route that builds a URL from req.query.url, resolves its hostname, blocks private IPs, fetches the URL with manual redirects, and returns the fetched text (500 on error).

The core bug is that the security decision is made on one resolved address, but the network connection is made using a later resolution that is no longer guaranteed to match what was validated. In other words, the application treats the hostname as a stable identifier, but the security property it checked was actually a property of a particular DNS response at a particular moment. A robust mitigation strategy is to ensure the check and the use are bound to the same concrete target, for example by resolving once and pinning the resulting IP for the subsequent connection or by performing validation at the exact point where the connection is established so there is no opportunity for the destination to change between those two steps.

For example, building on the scenario above, a safer approach is to ensure that the DNS resolution you validate is the one actually used for the network connection. In Node.js, one way to do this is to provide a custom request agent with a lookup function that performs the resolution and enforces the policy (for example, rejecting private IP ranges) at connection time, eliminating the “check here, use later” gap where the hostname can be rebound.

import { fetch, Agent } from "undici";

const dispatcher = new Agent({
  connect: {
    lookup: (hostname, options, cb) => {
      dns.lookup(hostname, options, (err, address, family) => {
        if (err) return cb(err);
        if (isPrivateIp(address)) return cb(new Error("blocked"));
        cb(null, address, family);
      });
    }
  }
})

app.get("/fetch", async (req, res) => {
  try {
    const url = new URL(req.query.url || "");
    
    // TRUNCATED: Verify the URL scheme (HTTP or HTTPS)

    // The dispatcher uses the valided resolution to establish a connection
    const r = await fetch(url, { redirect: "manual", dispatcher });

    res.send(await r.text());
  } catch {
    res.sendStatus(500);
  }
});
Code snippet showing a Node.js server setup using undici's fetch with a custom Agent and DNS lookup logic.

Most HTTP client libraries allow overriding the lookup mechanism, ensuring validation is also performed across redirects. If the library does not provide a way to override DNS resolution, you should pin the address used to establish the connection and disable redirects.

Exploiting a Single Resolution of the Domain

Operating principle

Even if the application resolves the attacker-controlled hostname only once, DNS rebinding may still be possible when that single DNS resolution returns multiple answers. Many HTTP clients treat the DNS lookup result as a set of candidate IPs rather than a single IP, and may try several of them until one succeeds.

Exploiting browser IP fallback

This variant of DNS rebinding does not require two separate DNS lookups. Instead, the attacker’s domain returns multiple records in a single response, typically one public IP address controlled by the attacker and one IP address for the intended target. Many clients treat multiple IPs in a DNS response as a list of candidates and “fail over” from one address to the next if the first times out, resets the connection, or otherwise fails.

In a browser context, the attacker can keep the first IP reachable just long enough to serve a page containing JavaScript. The browser ties that JavaScript to the origin defined by the attacker’s hostname, not to a specific IP address. Once the script is running, the attacker can trigger additional requests to the same hostname. When the browser tries to connect to the first IP again, the attacker forces that connection to fail (by closing the port, dropping packets, causing a timeout, etc.). The browser then retries the same hostname against the next IP returned in the original DNS response.

Because the hostname has not changed, the browser still considers these follow-up requests same-origin. However, they may now be sent to the second IP address (the internal target). This allows the attacker-controlled JavaScript to interact with internal HTTP services as if they were part of the attacker’s origin, potentially bypassing network-based controls (firewalls, IP allowlists) that assume browsers cannot directly reach internal addresses.

As a simple example, an attacker can configure their DNS server to return the following records.

attacker.example. 0 IN A $ATTACKER_SERVER
attacker.example. 0 IN A 192.168.20.4

The attacker can also host the following HTML on their server. It waits for the attacker to shut down the server, then sends another request to the same origin, allowing the script to interact with the internal server.

<h1>PoC DNS Rebinding</h1>

<script>
    setTimeout(() => {
        fetch("/", { cache: "no-store" }).then((x) => x.text()).then((x) => alert(x))
    }, 10000)
</script>

This exploitation works in Firefox: the attacker’s page remains open in the background while the internal server’s content appears in the alert. In effect, this mirrors the impact of an XSS vulnerability, allowing the attacker to fully interact with the application.

Proof-of-concept DNS rebinding page with a centered dark modal saying 'This is secret!' and an OK button on a gray overlay.
Attacker’s code interacts with internal server

This exploit does not work out of the box in Chrome because it implements the Private Access Network specification, which prevents a site loaded from a public IP address from accessing a private IP address. However, this does not mean the technique is obsolete. If the attacker is on the internal network or the target is Internet-accessible and the only barrier is a firewall, the attacker can still bypass the firewall by forwarding traffic through the victim’s browser.

To protect against these attacks, using a modern browser helps because modern specifications block or strongly constrain attackers. On the infrastructure side, DNS resolvers can mitigate this technique by detecting and filtering suspicious external hostnames that resolve to private addresses, preventing the victim from ever receiving the mixed response that enables failover. Finally, ensure sensitive web interfaces are exposed only over TLS, ideally with strict authentication and hostname checks, as this makes exploitation harder.

Conclusion

DNS is hard, and DNS rebinding is, at its core, a classic time-of-check to time-of-use (TOCTOU) bug.

The “check” is your validation step (e.g., resolving a hostname and deciding it’s safe). The “use” is the network connection that happens later, potentially after a new DNS answer, a retry, or a redirect. When those two aren’t bound, attackers can swap the destination under you.

Mitigations are the same as for classic TOCTOU vulnerabilities: validate at use time (enforcing policy in the lookup used to open the socket), or resolve once and pin the IP while tightly controlling redirects and retries. Because the victim’s browser is outside your control, you must rely on defense in depth to reduce the available exploitation paths. Browser-side protections such as the PNA specification, along with resolver-side filtering of public hostnames that resolve to private ranges, further reduce exposure.

Author: Arnaud PASCAL – Pentester @Vaadata

Partager l'article
Language

Stay connected!

Receive offensive security updates (selection of articles, events, training…)

Search

Tell us about your offensive security challenges and needs
Contact us to discuss your offensive security needs and get information about our services and processes. Our team will get back to you as soon as possible.