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

Disclosed: 2022-09-28 08:38:39 By zeyu2001 To nodejs
High
Vulnerability Details
**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.0`URL 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](https://en.wikipedia.org/wiki/0.0.0.0). 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](https://blog.scottlowe.org/2006/01/04/mac-os-x-and-local-domains) 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](https://thekelleys.org.uk/dnsmasq/doc.html) 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](https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml), `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](https://github.com/nodejs/node/blob/d9b71f4c241fa31cc2a48331a4fc28c15937875a/src/inspector_socket.cc#L164-L183) ## Supporting Material/References: - Original vulnerability: https://nvd.nist.gov/vuln/detail/CVE-2018-7160 - Code segment: https://github.com/nodejs/node/blob/d9b71f4c241fa31cc2a48331a4fc28c15937875a/src/inspector_socket.cc#L164-L183 ## 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.
Actions
View on HackerOne
Report Stats
  • Report ID: 1632921
  • State: Closed
  • Substate: resolved
  • Upvotes: 11
Share this report