An XSS on Facebook via PNGs and Wonky Content Types
fin1te.net
fin1te.net
And that's not meant to be a criticism, I'm just reflecting on my total ignorance of most security vulnerabilities. I know about and having implemented some measures against XSS / CSRF, but it's clear there are dozens of attack approaches I'm not even aware of.
I feel like I have some homework to do.
Usually this happens with content type sniffing (IE no MIME type is specified) but it leaves the door open to attacks like these. It changes the handler of the input from code designed to care about security (IE your upload handler code) to code designed to care about usability (MIME sniffing heuristics, or in this case the decompression/rendering library).
When this happens you usually get bad/unexpected results, but it makes it easy to figure out where you can stop caring about implementation details- when the user input leaves the area of the code designed to secure it!
I'm currently taking a security class and what I'm noticing is that I mistake the complicatedness for complexity but in essence most vulnerabilities and attacks have the same high level overview.
What I'm trying to say is: don't feel so bad, if you understood 25%, then you know more than you think. Perhaps you too are captured by the complicatedness of his post ;)
You conjugated the same word two ways. What do you mean?
Complex -> complexity
On the other hand, complicatedness is a verb turned into an adjective turned into a noun.
Complicate -> complicated -> complicatedness
I read that as an implication that security concepts are not inherently difficult but are made difficult by people who explain it incorrectly.
Here's a fun example. English has a lot of Latin and Germanic based words in it that you can construct entire sentences. I was surprised to find out as a non-native speaker. In my opinion, the Latin sentences seem way too complicated to express simple ideas.
Germanic example: In my anger I struck my small sword in his belly.
Latin example: In my rage I injected my gladius in his abdomen.
More examples: http://corrinejackson.com/wordpress/2013/04/23/tuesday-writi...
1. Allowing something that is not HTML (and user-supplied) to be returned by the server with the text/html MIME type, causing the browser to want to parse it as HTML.
2. A link between the CDN (Akamai) domains and a top-level sub-domain on Facebook (i.e. photos.facebook.com was aliased to some Akamai domains).
At this point the attacker is able to serve HTML from a Facebook domain. There are things that could be protected against here, but the attacker has a lot of vectors they can go for at this point.
> I feel like I have some homework to do.
Start with X-Frame-Options and HttpOnly cookies.
1. Don't serve user supplied content from a subdomain of your main site. Facebook fixed this by removing the redirect from photo.facebook.com to their CDN, so now user content comes from *.akamaihd.net.
2. If a user uploads a PNG (or whatever), and you've validated it for that content type, don't serve it from your servers with a different content type. Clever users can make files that browsers will handle in different ways for different content types. Facebook's CDN still seems to allow serving files with the wrong (unvalidated) content type just by changing the file suffix in the URL.
I don't see that as an issue. As long as you don't allow for wildcard extensions on your server it won't return a wrong content-type in this kind of situation. I wonder why it's even possible that you can change the .jpg to .html :| I'm pretty sure this is disabled by default in apache.
> don't serve it from your servers with a different content type.
so yeah, the problem of the content-type comes from the fact that you can manipulate the extension as you wish once uploaded.
Is this common practice amongst websites? seems like a weird config to have enabled.
Crucially though, is they removed the DNS forward to the CDN. Which means they're actually storing .html files on those CDN servers. For ads, presumably, but it seems terribly silly to be storing .html files there at all.
I can see changing the suffix for image types and converting the image on the fly - I don't know why that would be useful, but I can imagine someone doing that. But at the very least don't allow sending something you know to be an image with non-image headers.
(Assuming it had been found by a "bad guy", instead of a white-hat researcher.)
Because:
* He could execute arbitrary code in the browser of any user that views his picture
* Including uploading all private photos and chats of that user to somewhere else
* Or changing their password (assuming 2FA is not used)
* He could have propagated this exploit to all Facebook users by simply uploading his XSS picture into his victim's profile, and from there into second-degree victims, and so on? According to the "6 degrees of separation" theory, this would have been very fast
Or am I missing something?
It seems that you click "download" on Facebook images, you'll get redirected to a CDN URL. So there's that. You could see what images the user is trying to download and edit them in flight... not a big deal, but it's something.
If you could create a valid ServiceWorker at this route, and load it inside some same-domain HTML page, then you could theoretically use it to intercept and rewrite responses to any resources on the domain under its path. Depending on how you rewrite the response you might be able to get the browser to cache the rewritten resource, which could then get used by other domains. Theoretically. I have never tested this :)
As I said, the text/javascript Content-Type is another one the CDN is willing to serve if you change the extension. I'm silly and didn't think of the fact that unlike HTML, a JS file can't be random binary garbage with a payload embedded somewhere in the middle. However, I am not sure that some allowed image format doesn't allow putting, say, // close enough to the beginning of the file that it will work. It seems like it might be possible with the JPEG header, but of course it depends on the post processing done. (Or maybe there is some way to upload non-images?)
"Service Workers are restricted by the path of the Service Worker script unless the Service-Worker-Scope: header is set" [1]
I do wish the spec required a 'Content-type: text/service-worker', as that would effectively eliminate accidental ServiceWorkers as a threat.
[1] https://infrequently.org/2014/12/psa-service-workers-are-com...
https://slightlyoff.github.io/ServiceWorker/spec/service_wor...
> Rather than trying to create this by hand, I used a brute-force solution (I’m sure there are much better ways, but I wanted to whip up a script and leave it running):
He just didn't want to learn DEFLATE right then, right there. He got the same result.
FWIW, I don't think this is actually hard. DEFLATE has a small header that tells you want type of compressed data follows; one of the types is "literally, this data" which is up to 64KiB long. (i.e., a plenty long enough string to get the job done.)
Fix
Facebook quickly hot-fixed the issue by removing the forward DNS entry for photo.facebook.com.
Am I missing something, or the attack assumes you can convince a victim to go to the given URL through other means? Like spreading through IM, E-mail...
A CDN absolutely mustn't allow a user to browse to a file with a different extension than it was uploaded with. It must return 404 in this case. II think the flaw is much more severe than has been discovered.
Anyway, CSP clearly isn't useless... but try deploying it on your average Wordpress blog sometime.
Are you sure ONLY? Enable CSP on a XSS-vulnerable website, send a payload, CSP prevents XSS from executing if your policy say so.
What issues have you found with this?