"Bypassing" CSP’s Data-Exfiltration Protections

A long time ago now, I tweeted a challenge to see of anyone knew what the following URL would attempt to do:

Don’t worry, I don’t expect you to stare at that monstrosity. Instead I’ll just tell you;
So a friend of mine was competing in WhiteHatRally last year, which is a sort of “solve the clues to figure out where to go”-style car race for charity, and he realised that it might be possible to stalk the other competitors, who were displaying there progress on FB via GPS tracking site insta-mapper.com, in order to determine where they were going and beat them there. So initially we looked at spending a weekend making an app to cheat at a charity race by scraping the other contestant’s locations in semi-real-time… we’re that cool. But I ended up spending the weekend learning the ins and outs of Content Security Policy (CSP) instead, which actually is quite cool. In this post I’ll explain what a learned about CSP that stopped our attack, and how we were still able to ‘bypass’ it and skin the cat a different way.In failing to make an app to cheat at a charity race I noticed that the site had pretty dyer input validation and pretty much everything was vulnerable to XSS. This was a prime example:
We realised that an even more effective form of cheating would be to compromise the insta-mapper accounts of the other contestants using this XSS, and get a better look at where they were and where they were going.. and so we went from making an app to cheat at a charity race to directly attacking its competitors :/ Its weird how comfortable I was with this.
The site had “connect-src” & “form-action” directives in the CSP headers, with values pointing to the site’s own origin. What on earth do they mean? I thought CSP was for blocking XSS?! Well… take a look at these:

  • "connect-src" limits the origins to which you can connect (via XHR, WebSockets, and EventSource).
  • "form-action" lists valid endpoints for submission from <form> tags.
  • "child-src" lists the URLs for workers and embedded frame contents. For example: child-src https://youtube.com would enable embedding videos from YouTube but not from other origins.
  • "img-src" defines the origins from which images can be loaded.
  • "media-src" restricts the origins allowed to deliver video and audio.
  • "font-src" specifies the origins that can serve web fonts.

So utilising ALL of these directives, a site can, quite effectively, prevent itself from being used as a base for CSRF against another site, and can prevent data exfiltration from its own pages. Cool!
Now, the insta-mapper app only uses two of these directives, and the others give us clues as to how we might still be able to get data out. We could, for example, inject an image whose location is at evil.com and the file-name is the victim’s session cookie, then simply scrape that from our access logs. But, as a thought experiment, lets assume that insta-mapper used ALL of these directives… then what?
This would mean that, while we have XSS which can grab the session cookies, we can’t actually ex-filtrate them out of the application to evil.com, drats! Although, and this is the semi-obvious, yet not so obvious, bit… we don’t hardly ever need to get data OUT of an application, we just have to COPY it somewhere we can see it. With that in mind, this is what the URL above does:
Makes and AJAX post to the registration page for insta-mapper.com (same origin, totally allowed), creating a new account with a User/pass that we define.. and registers a tracking device for that account with the name of document.cookie.
BOOM! All we have to do is send a victim (aka; a nice person who has spent their weekend doing something good for charity) this link, log-in to the account we made them set-up, and look at the account’s device name, which will be the session cookie for the victim!


As a side: If the site you’re pwning uses JQuery or you’re able to bring it in yourself, do yourself a favour and do it. The AJAX functions will make your payloads/attacks smaller and work better across different browsers, rather than including a mess of 10-year-old JS you copied from the web. Its just as reliable as injecting an auto-submitting form these days and wont redirect the browser 🙂

Update: I sent Google’s Mike West my thanks for his CSP write-up on HTML5rocks.com and pointed him to my post. He directed me to a blog/paper Michal Zalewski (@lcamtuf) published back in December of 2011, which talks about the many ways in which an attacker can perform content exfiltration. It looks like, at the time, CSP was really only an XSS defence.. but has since grown to include all of the above directives which, one-by-one, work to solve the data egress methods Michal talks about. We both came to the same conclusion in our posts though, that same-origin content exfiltration is going to be damn-near impossible to protect against.  I’d thoroughly recommend reading his paper: http://lcamtuf.coredump.cx/postxss.