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.