Tuesday, May 10, 2011

Remember how it was possible to upload files with arbitrary names & contents cross domain? The method had one, but crucial limitation - it did not include any credentials. In other words, the POST message would be sent to server without any cookies / HTTP auth, so it would most likely be discarded by the attacked application. You could upload a file (precisely, that's a CSRF File Upload), but, in most cases, the receiving application would drop it. Until now :)

I can haz cookies!

I still don't know how did I miss this, but it's just a one-line change:

Luckily for attackers (and unfortunately for the Web), POST request with MIME type multipart/form-data and credentials are still in the 'simple' bucket. So the exact CSRF CORS File Upload attack works like this:

"Take those cookies to your grandma", said The Browser

Victim logs in to victim.whatever.com website

He receives a session cookie for future requests

In the same browser session (e.g. 2nd tab) he visits attacker.reallybad.ly website

"Browser, I really need you to send this tiny little harmless POST to victim"

Browser treats this as a simple CORS request, so it attaches the cookie for victim domain to it and sends it.

"Hey, JS! It's a request to another domain - what are you up to? Oh, just a POST request? No custom headers? Sure thing, here are the cookies and I wish you a pleasant journey!"

victim app receives the POST file upload with the cookie, so it processes the upload and responds.

"What's this weird Origin header pointing to attacker.reallybad.ly? It must be the new kid in town, but who am I to know?"

Browser looks at the response and, not having appropriate CORS response headers, discards the response.

"Oh dear! No Access-Control-Allow-Origin header at all! You bad Javascript! I won't give you the response, and you'll get spanked with an exception! Surely that was one nasty hack attack I prevented. Luckily I follow the CORS specification, good work, CORS guys!"

Yeah, exactly. Good work! Now the CSRF File Upload is super-simple. I've updated theexamples with the new code.