HexBrain

Node.js · Report #1632921

DNS rebinding in --inspect (insufficient fix of CVE-2022-32212 affecting macOS devices)

Validstatus
highseverity
16upvotes
28 Sept 2022disclosed

How it was found

Summary: This is an insufficient fix of CVE-2022-32212, which itself is a fix of CVE-2018-7160. There exists a specific behaviour in browsers on macOS devices when handling the http://0.0.0.0URL that allows an attacker-controlled DNS server to bypass the DNS rebinding protection by resolving hosts in the .local domain.

Description:

In the latest version, only IP addresses and localhost are allowed in the Host header when connecting to the debugger endpoint. IsIPAddress ensures that IPv4 address octets only contain values ranging from 0 to 255, but this allows 0.0.0.0 which indicates an invalid or unroutable target.

In macOS devices, using fetch("http://0.0.0.0")or opening http://0.0.0.0 through a top-level navigation in Chrome and Firefox will cause a DNS request to resolve <Computer Name>.local, where Computer Name is configured in the system preferences (the use of the .local TLD is a known feature of macOS devices). If such a request succeeds, http://0.0.0.0 is routed to the IP address provided in the DNS reply. This would typically be the same as the IP address of the device on the local network, so http://0.0.0.0 will typically route to any application listening on the local interface - working as intended.

An attacker-controlled DNS server can, however, resolve <Computer Name>.local to any arbitrary IP address, and consequently cause the victim's browser to load arbitrary content at http://0.0.0.0. This allows the attacker to bypass the DNS rebinding protection.

Note: On Windows devices, http://0.0.0.0 is treated as an invalid URL and the request is blocked.

Steps To Reproduce:

General Attack Flow

  1. Victim runs node with --inspect option
  2. Victim visits attacker's webpage
  3. The attacker's webpage opens http://0.0.0.0:9229
  4. Victim asks the DNS server for <Computer Name>.local and gets <attacker's-IP>.
  5. Victim loads webpage http://0.0.0.0:9229 from <attacker's-IP>.
  6. The webpage http://0.0.0.0:9229 tries to load http://0.0.0.0:9229/json.
  7. Due to a short TTL, the DNS server will be soon asked again about an entry for <Computer Name>.local. This time, the DNS server responds with "127.0.0.1".
  8. The http://0.0.0.0:9229 website (i.e., the one hosted on <attacker's IP>) will retrieve http://0.0.0.0:9229/json from 127.0.0.1, including webSocketDebuggerUrl.
  9. Now, the attacker knows the webSocketDebuggerUrl and can connect to it using WebSocket. Note that WebSocket is not restricted by same-origin policy. By doing so, they can gain the privileges of the Node.js instance.

Vulnerable code segment: https://github.com/nodejs/node/blob/d9b71f4c241fa31cc2a48331a4fc28c15937875a/src/inspector_socket.cc#L164-L183

DNS Setup

In this example I used dnsmasq as my DNS server. You can use {F1816108} for a minimal Docker setup that demonstrates the arbitrary resolution of <Computer Name>.local domains. The hosts file should be changed according to the configured Computer Name of the victim device (through system preferences). For example, my Computer Name is Zeyu’s MacBook Pro, which means I had the Zeyus-Macbook-Pro.local domain.

# Resolve <Computer Name>.local to any IP address
1.1.1.1 Zeyus-Macbook-Pro.local

When connecting to http://0.0.0.0, the page is loaded from 1.1.1.1 instead.

{F1816116}

If you observe the network traffic while connecting to http://0.0.0.0, you should see the relevant DNS requests and replies.

{F1816134}

Subsequently <Computer Name>.local can be rebinded to 127.0.0.1, causing the page to be loaded from 127.0.0.1 where the debugger is listening.

{F1816125}

Suggested Remediation

According to IANA, 0.0.0.0/8 is a reserved address range. To prevent this vulnerability, this address range could be blocked.

A way to check for this address range could simply be accum == 0 in the first octet or host.front() == '0' in IsIPAddress

Supporting Material/References:

Impact

Attacker with access to a compromised DNS server or the ability to spoof its responses can gain access to the Node.js debugger, which can result in remote code execution.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original