Flash and the Same-Origin Policy

Web browsers protect the user from attacks largely through the same-origin policy: any code from one web site (such as HTML pages or JavaScript) is not permitted to interact with any code from another web site. I can make a web page that embeds a Hotmail window in the middle of it (with an IFRAME), and you’ll see your Hotmail in the window — but my page’s script is not permitted to read or write what’s in that window. Without the protection of the same-origin policy, using the Web for commerce or anything at all sensitive would be impossible — you would never know when a site you access might try to log into your bank, or your email, without you even noticing. Since your browser supplies your cookies to sites automatically, if a site could script against another, it could do so as you with all your privileges. Luckily, all browsers do enforce the same-origin policy. But what about things that aren’t browsers, but live inside them? A lot of rich content on the web, including many advertisements and all the videos on YouTube, are actually Adobe Flash applications. Others are Java applets. Though they’re embedded in your browser, they’re not the browser itself — so the browser can’t enforce the same-origin policy on them. However, we’re still safe, because Adobe and Sun have been smart enough to build the same-origin policy into the Flash and Java runtimes. They also check to make sure a web page can communicate only with the site it came from, not other sites. However, Flash and Java provide many things a regular browser cannot, and they’re frequently used in enterprise applications where cross-site communication is desirable. In addition, sometimes you actually want other sites to be able to script against you. If you’re a public web service and you want your components to work in mashups, you have to allow some cross-site access. To enable this, Flash allows web servers to place a file called crossdomain.xml on their server, which contains XML that looks something like this:

<cross-domain-policy>
<allow-access-from domain=”www.domain1.com”>
<allow-access-from domain=”www.domain2.com”>
</cross-domain-policy>

With this code present on a site, that site becomes accessible to any Flash application on domain1.com or domain2.com. Wildcards are allowed, including putting in the domain “*”, which means any site on the Internet can script against it. This is a legitimate thing to do if your site is a public API without authentication (e.g. Google Maps.)

However, it’s quite dangerous to do to a site that isn’t fully trusted. It is critical that crossdomain.xml not allow any more sites than necessary, because of the risk that relaxing the same-origin policy entails. If, say, an online bank were foolish enough to allow “*” or some easily-manipulated domain (i.e. one with a lot of user-uploaded content, like a social network or a forum), then anyone able to add content to that domain could upload a Flash applet that would connect to the bank as the user, using the user’s cookies, and perform whatever tasks it wanted — invisibly, with no sign to the user anything is going on. (Just because Flash apps usually have an appearance onscreen and are used to render graphics doesn’t mean they have to be; a Flash app is just a program.)

However, there are two serious problems with this method of relaxing the same-origin policy — and either of these can allow a malicious website to “relax” the policy of another site against its will. In each case, it involves combining another well-known attack (cross-site scripting in one case, DNS rebinding in the other) with the Flash security model to produce a vulnerability.

Cross-site scripting is the term for any vulnerability where user input is echoed back to the user (either the same user or a different user) from the site without proper sanitization. For instance, if I ask the user for his name, and he answers “<script language=”JavaScript”>alert(“Hello!”);</script>”, and from this I create a web page that says “Hello (name)” to him, he’ll get a pop-up on screen, because the “name” is actually code that, when it comes from the web server, is executed. This is a problem for the same-site rule because that code comes from the web server — instead of just popping up a dialog, it could have manipulated the web site and performed tasks on the user’s behalf! According to the same-origin policy, it’s “safe.” Now, in this scenario this sounds pretty harmless — after all, he’s attacking himself — but what if another page on the site allows any user to see a list of everyone’s name? Or what if it’s a forum and the user’s name is displayed on every post? Now that attacker’s code is running for everyone, in each case as themselves and able to take actions on their behalf.

How does this relate to Flash? Well, the crossdomain.xml file can be located anywhere on the server — the Flash applet chooses where to load it from. So if I can use a cross-site scripting attack to make a file on the web server that looks kind of like a crossdomain.xml file, I can tell my malicious Flash applet to load and apply that policy. (The filename doesn’t have to be crossdomain.xml — it can be kittens.jpg if I want. As long as it’s on that server, it can grant access to that server if the Flash applet knows where to find it.) There’s a good illustration of this attack on the Hardened PHP Project.

The other, and far scarier, attack is to use DNS Rebinding. The same-origin policy means you can only load from the site with the same domain name, like perimetergrid.com. But pages really load from IP addresses, not names. The DNS system translates names to addresses. However, the DNS system is federated — there’s no one master library of all DNS names. When you try to go to a site, your computer asks your ISP’s DNS server for its IP address, and the request is forwarded to the authoritative DNS server for that name. That DNS server then replies with the IP. If I wanted to (I don’t), I could set up my own DNS server that I control, have the root DNS point perimetergrid.com there, and then have my DNS server respond to any lookup up my site with any IP I wanted. The web browser would then load that page, and proudly display it as “perimetergrid.com,” because it trusts DNS.

Malicious DNS servers can do many horrible things. Imagine this process:

  1. I load up a web forum. Someone has made a post with an embedded Flash applet.
  2. The Flash applet loads from evil.com, and then it gets a crossdomain policy from evil.com (IP 6.6.6.6. Note that I don’t mean the real web site “evil.com”, but am just using the name to stand in for some malicious site.)
  3. Evil.com, which is a malicious site with a malicious DNS server, responds with a crossdomain.xml that allows script from “*”. Now my Flash applet is allowed to script against evil.com.
  4. The Flash applet now tries to load a web page from evil.com again. However, the malicious DNS server instead returns the IP address of your mail server, or your bank, or somesuch.
  5. The Flash applet on your computer loads the page right up and can script against it. After all, it’s just evil.com, which it knows from step 3 is safe for scripting. It gets the data it wants, using your credentials, without your knowledge.
  6. The Flash applet sends the data back to evil.com — which this time returned its real IP address so it could receive the communication.

This is really hard to defend against. We assume that DNS can be trusted, but DNS was not designed with security in mind and will never be secure. Evil.com could even have returned IP addresses inside your local network, behind your firewall and the browser and Flash applet would dutifully access them.

There are some techniques called “DNS pinning” that help mitigate this, by not allowing the DNS to return different IPs in rapid succession. The problem is that they break load-balancing — when you access a major online property with hundreds of servers, your request probably really is handled by many servers, all of which have the same name. Breaking this attack also breaks Google and Microsoft and Facebook.

Luckily, Adobe is aware of the issues and in Flash 9 has some mitigations proposed, including forcing socket access to get cross-domain policy by IP rather than by name. There’s a full whitepaper about it on Adobe’s site that’s a good read; Adobe is quite security conscious and has a mature security model for Flash, it’s just very hard to stop these sorts of design flaws in the web. Restricting socket access will help a lot — at least a malicious app won’t be able to port-scan behind your firewall and perform network attacks, though it could still browse web pages. This is an arms race between attackers and software companies that will continue quite a while.

attacks, risk

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.