CSRF: Flash + 307 Redirect = Game Over

 

A vulnerability for Ruby on Rails was recently patched [http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails].
The default CSRF prevention built into RAILS had two components: (1) a custom HTTP Header, and (2) a CSRF token in the post body. This was implemented in a way that only one of these components were required in a request, and not both. Modern browser security makes this fairly secure because JavaScript cannot create custom HTTP Headers and have them sent across domains. However, a researcher from Google found that there is a way to exploit this issue using "certain combinations of browser plugins and HTTP redirects". The new patch for Ruby on Rails forces both of these components to be in the request, preventing exploitation.

A hidden flash file on a website will automate the sending of the following request:

http://www.attacker.com/redirect.php?status=307&url=http://www.victim.com

Flash will allow the site which it is running from to specify POST data and additional headers. But before sending the request, it will check the sites crossdomain.xml file. The attacker will set up their cross domain.xml file as follows.

http://www.attacker.com/crossdomain.xml

---
<?xml version="1.0" encoding="UTF-8"?>
<cross-domain-policy>
	<allow-access-from domain="*"/>
	<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
---

The flash file will understand that it now has permission to send additional header information with its request, and will proceed with sending the request with extra headers to

[http://www.attacker.com/redirect.php?status=307&url=http://www.victim.com]

The attacker site will return a 307 redirect. It's like a 302 redirect, but allows the forwarding of POST data too. The flash application will realize that it is going to another web server, and will attempt to retrieve the crossdomain.xml file for www.victim.com. Unfortunately, it appears that it certain circumstances, Flash will IGNORE the crossdomain.xml file for victim.com, and instead rely on the original crossdomain.xml file at www.attacker.com. After a confirmation message that will be unclear to most users, the flash application sends a new request.

------------------------------
POST / HTTP/1.1
Host: www.victim.com
…
X-Header: test=data;
Cookie: abc=123
Content-Length: 9

post=body
------------------------------

We see here that the POST request is being set to www.victim.com, with the additional headers and the POST body. Web server frameworks can no longer rely on the implied security of additional HTTP Request Headers alone to prevent CSRF.

Breakdown of the vulnerability:

Mac - Flash Player 10,2,154,12
	Chrome 9.0.597.94		302 Redirect		GET Request, with headers
	Chrome 9.0.597.94		307 Redirect		Not Sent
	Safari 5.0.3 (6533.19.4)	302 Redirect		GET Request, with headers
	Safari 5.0.3 (6533.19.4)	307 Redirect		POST Request, with headers (No Confirmation)
	FireFox 3.6.10			302 Redirect		GET Request, no headers
	FireFox 3.6.10			307 Redirect		POST Request, with headers
	FireFox 4 beta 8		not vulnerable

Windows XP - Flash Player 10.2.152.26
	FireFox 3.6.10			302 Redirect		GET Request, no headers
	FireFox 3.6.10			307 Redirect		POST Request, with headers
	IE 7				not vulnerable
	IE 8				not vulnerable

Testing the vulnerability yourself:

1. Setup a local HTTP proxy, such as Burp Proxy.
2. Run the attached crossdomain.swf application from your browser (Credit goes to my colleague, Jason for writing this awesome tool)
3. For the URL, use a redirect. I have one set up here: [http://nevr.co.cc/xss.php?status=307&redir_xss=] where status can be tested as 302 or 307, and the site you want to test it against is after the "redir_xss" parameter
4. Test different combinations of requests, and look at the request/responses as they go through your HTTP proxy application.

Strange Behavior Inside Tags

Here is a really strange bug that appears to be fixed in the latest web browser versions.

Some browsers will actually render <script> tags inside of <link>, <a href>, <div>, <img>, and possibly many other tags. See some examples on my test page. If you are running a vulnerable browser, some alert boxes will pop up. If you are running a browser where the bug has been fixed, then you won't really see much except some broken HTML code. Make sure to view the source of the page to see how the test site was setup.

Update 9/22/2011: I noticed that many mobile browsers are vulnerable to this bug, including iOS and Android Browser.

Encoding Problems

Can you trust your web browser? Many web browsers have bugs that cause them to render some characters from different character sets incorrectly. The following pages will demonstrate these bugs by example by showing how Despite what your browser may display on the following pages, none of the linked pages are <script> tags might be inserted even if the " < " and " > " are properly filtered by the web server.

Encoding TypeVulnerable BrowsersVulnerable CharacterUnicode GraphicComments

UTF-7IE6, IE7, IE8, FireFox < 4Nothing crazy here, just normal UTF-7 encoding

X-IMAP4-MODIFIED-UTF7FireFox < 4Nothing crazy here, but a strange character set nonetheless

X-MAC-FARSIFirefox < 3.6.13[\xBC]☼☽☾Variable Width Characters are improperly decoded

X-MAC-ARABICFirefox < 3.6.13[\xBC]ټVariable Width Characters are improperly decoded

X-MAC-HEBREWFirefox < 3.6.13[\xBC]ּלVariable Width Characters are improperly decoded

Shift_JISIE6*, IE7*, Firefox, Opera[\x81]?Multi-Byte Character indicator clobbers the double-quote *IE is affected when the Japanese language packs are installed

UTF-8IE6, Opera < 11.0[\xC0]À, タMulti-Byte Character indicator clobbers the double-quote

US-ASCIIIE6, IE7[\xBC]¼, シIncorrectly reads an 8-bit character

Tip: If you still don't "get" whats going on here, check out some of these vectors in a webkit browser like Safari or Chrome.