
Flash + 307 redirect = Game Over - ssclafani
http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html
======
tptacek
Doh! Sam Quigley called it. In the 307 redirect case, which instructs the
client to redirect POST data as well as the bare request, Flash can be coerced
into honoring the crossdomain.xml file from the REDIRECTOR site instead of the
REDIRECTEE site.

* Attackers control redirectors (they can just set up their own).

* Flash will set custom headers if crossdomain.xml allows them to.

* Rails and Django rely on the fact that attackers _can't_ send custom headers (in particular, the XRW header that told Rails and Django "this is Ajax, don't worry about CSRF").

* So attackers can basically forge the crossdomain policy for arbitrary target sites using Flash, bypassing the CSRF security check in Rails and Django.

So much win!

~~~
paulhammond
This explains a lot, but thing it doesn't cover is why the patch for Rails
ends the session when a CSRF token is missing.

I'm guessing this is just extra paranoia, but it opens an obvious attack to
log people out of a site maliciously.

Any ideas on that one?

~~~
smunz
I guess they forced the end of the session to allow non-session
authentication, for example for an Client accessing an RESTful API.

I didn't found anything about this, but when you look at the related commit in
rails
([https://github.com/rails/rails/commit/66ce3843d32e9f2ac3b1da...](https://github.com/rails/rails/commit/66ce3843d32e9f2ac3b1da20067af53019bbb034#L1L144))
they also removed the white listing an all non html-requests
("content_mime_type.verify_request?"). So any (api) client modifying XML or
JSON resources of an rails app would not be allowed to do so, because of the
need to provide the authentication token. Which isn't available for an API
client, because there is no session.

So instead of throwing an exception to prevent an CSRF-attack they just kill
the session to prevent authentication by this session. For an api client this
is no big deal, because normally it authenticates with per request
credentials.

If you don't feel/have the need to support non session authentication, my
guess is you could simply overwrite the handle_unverified_request method in
your application controller to throw an exception again. But I would wait for
further explanation by the rails core team.

------
euroclydon
This is so difficult to follow.

1) Who hosts the flash app? The site owned by the attacker? Or must the flash
app be maliciously uploaded to the site being attacked?

2) And seriously, the final result of this scheme to to make a post to
"www.victim.com". Doesn't "victim" mean someone who is exploited? I would
expect that data would be taken from a victim, not posted to a victim.

~~~
nbpoole
It's actually fairly straightforward

1\. It doesn't matter where the SWF is, as long as it can make requests to a
redirecting script. That's the point of the attack: you can make cross-domain
requests via a redirect.

2\. Victim is referring to a victim domain. Pretend victim.com is your bank,
and the POST is to send some cash to my account.

~~~
euroclydon
So my bank would have to already have a page which returns a 307?

~~~
nbpoole
No. Let me try explaining the simplest possible version of this attack.

Your bank (<http://victim.com>) is running its external-facing web application
on Ruby on Rails. If you send a POST request to <http://victim.com/transfer>,
you can transfer money to another person (the recipient is specified in the
POST body).

The attacker sets up the following things on attacker.com:

1\. A page that replies with 307 redirects to a specified destination

2\. A Flash applet that makes POST requests

3\. A page embedding that applet

The attacker sets the applet as if it were making a POST request to
<http://victim.com/transfer>, setting the X-Requested-With header to bypass
CSRF protection. But instead of POSTing directly to victim.com, the attacker
POSTs to the redirect script.

So the end result looks something like this:

1\. Flash checks to make sure that it can make requests to attacker.com (via
crossdomain.xml, or by the same origin policy). It can.

2\. POST request to attacker.com/redirect is made

3\. attacker.com/redirect says "307, the request should go to
<http://victim.com/transfer>

4\. Flash says "OK" and makes the same request but now directed at victim.com

5\. After the request has been made, Flash checks the crossdomain.xml file and
says "whoops, shouldn't have made that request: you can't see the response."

~~~
ben_h
Good explanation, thanks.

The part I don't understand is the POST hitting the victim app. I don't know
django but rails apps require an authenticity token to be included in all non-
GET requests. How does the attacking app satisfy this token check?

~~~
euroclydon
Rails WAS configured to accept the token OR a custom header, relying on the
fact that custom headers can't be created cross domain. The patch fixes this,
by requiring BOTH. Hmmm... So how do they know what the custom header is? Are
they typically static?

~~~
cheald
The CSRF token is generated and stored in the user session, so rather than
just X-Requested-With: XMLHttpRequest, you now also get an X-CSRF-Token: <some
token stored in the user session>.

Rails doesn't check for XRW anymore; it just cares that you passed a valid
CSRF token through, either as a POST variable (normal POST/PUT/DELETE) or in
the X-CSRF-Token header (AJAX).

In case you're wondering, yes, this does make caching with Varnish a bitch and
a half.

~~~
euroclydon
I want know how the exploit works. The Flash app has to write a custom header.
How does it know the value to put in the header, unless it's always the same
for all sessions across all users.

P.S. You cache POST/PUT/DELETES?

~~~
cheald
That's the point of the fix. The header is custom per user now. Before, the
presence of the "X-Requested-With: XmlHttpRequest" header was enough to let
Rails assume the request was legit. Since Flash doesn't respect the victim's
crossdomain.xml, this is no longer a valid assumption, and you have to use a
unique header per session.

This means writing this unique value out into the page somewhere, to be
included with any AJAX requests, which means that you cannot cache these pages
as you might before, since AJAX calls would fail for everyone except the
person who populated the cache.

------
jodrellblank
_After a confirmation message that will be unclear to most users_

i.e. it requests permission?

------
sdizdar
I have a stupid question: Does this vulnerability exist if rails runs https?

~~~
nbpoole
Yes

------
wnoise
Hooray flashblock.

~~~
amalcon
Flashblock would probably not save you. It doesn't actually prevent Flash
content from being downloaded and run; it just hides it with CSS.

I use NoScript myself, but that tends to break too much by default for most
people. When I set up a flash blocker for other people, I give them NoScript
in "Allow Scripts Globally" mode.

~~~
nbpoole
Are you sure about that? Because that's not the way Flashblock describes
itself:

    
    
        Flashblock is an extension for the Mozilla, Firefox, and Netscape browsers that takes a pessimistic approach to dealing with Macromedia Flash content on a webpage and blocks ALL Flash content from loading. It then leaves placeholders on the webpage that allow you to click to download and then view the Flash content.
    

It would be pretty useless if all it did was hide the content via CSS.

~~~
amalcon
Wikipedia cites this as the source for that assertion:

<http://flashblock.mozdev.org/faq.html#fbFlashCookies>

If it prevented the object from loading, it would block Flash "cookies".

edit: Looks like it does call StopPlay() on the movie, which prevents any
audio/visual effects.

~~~
nbpoole
I just tested the extension and I can confirm that Flashblock only downloads
and runs the content when the placeholder is explicitly clicked on. So,
Wikipedia is wrong. ;)

Edit: If I browse to an SWF directly, it does appear to load the content. If I
create the SWF via SWFObject, it does not load until I explicitly click on the
placeholder.

That question is poorly worded. It's referring to blocking Flash cookies in
general. Flashblock will not prevent the use of Flash cookies by applets that
you allow to run.

------
EGreg
Why don't they use the session nonce instead of double-submit cookies approach
to CSRF prevention?

