Mozilla Firefox - Referer Spoofing Using JavaScript

Summary

Versions of Mozilla Firefox prior to 2.0.0.10 are vulnerable to a race-condition when setting 'window.location' values using JavaScript. In some circumstances, the race-condition can be exploited to spoof referer headers. Specially crafted iframe content can be used to perform cross-site request forgery (CSRF) against sites that accept GET requests and use referer checking for protection.

Attack Goal

The goal of the attack is to have an iframe pointed to one site and then cause the iframe to load a second location. The first site's location should become the referer header when requesting the second location's content. These locations could be on different sites, the same site or even the same page. If this can be accomplished, the attack can be used to defeat simplistic cross-site request forgery (CSRF) protections that depend entirely on the referer header.

Background

In general, Firefox attempts to prevent an iframe's parent from reading/writing content in the iframe's browsing context once the the location is changed. When an iframe location is updated, the iframe is submitted with a referer value of the parent's location. The parent's access to the iframe content is lost once the location is changed, but the parent can continue to exert control over the iframe by changing its location or creating new content. Additionally, if the iframe's new location is set from within its own browsing context, the previous location becomes the referer header value.

There have been several past vulnerabilities related to iframes (e.g., Michal Zalewski's IFRAME snatch, Bugzilla entries #381300 and #343168). These vulnerabilities show that there is a small window of time where the iframe context may be exposed. Using 'setTimeout' or 'setInterval' to load the second location would seem like obvious candidates, but the timers are cancelled once the existing iframe page is unloaded.

But what if the timing approach is inverted? Instead of using a timer to load the second location, a timer is used to the load the first location in the background. Then, once the first location is loaded, the current location is set to the desired site (thus causing the first location to become the referer). Normally this should be impossible, because the iframe should not have two browsing contexts at the same time. But, if the user is presented with 'alert', 'confirm' or 'prompt' dialog and the original iframe's context is persisted long enough for the first location to finish loading, the 'window.location' can be set to the second request; this second request will be submitted with a referer value of the first location.

Realizing the Attack

The following are two approaches to the attack:

Joke Method - The iframe content is written as JavaScript that starts a timer to change the location to the desired referer. The 'window.onload' event is set to function that opens a 'confirm' dialog and then sets the iframe location to the target. If the first location loads before the 'confirm' dialog is dismissed, the race is won and the referer header is set to the first location.

Winding Paths Technique - The iframe content is set to HTML and JavaScript that uses a meta refresh to load the desired referer after one second. A timer is set so that before the page refreshes, a function is fired that presents the user with an 'alert' dialog; once the 'alert' is dismissed the iframe location is set to the target. If the first location loads before the 'alert' dialog is dismissed, the race is won and the referer header is set to the first location.

Attack Matrix

Which attacks work with what user agents?

User Agent Joke Method Winding Paths Technique Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 Yes Yes Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 Yes Yes Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 Yes Yes Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9a9pre) Gecko/2007110504 Minefield/3.0a9pre No Yes Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O 10.4; en-US; rv:1.9a9pre) Gecko/2007110504 Minefield/3.0a9pre No Yes Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a9pre) Gecko/2007110505 Minefield/3.0a9pre No Yes

Notes

Only the GET request method seems to be affected. There does not appear to be any mechanism to submit POST data.

If the user's browser is configured to not submit Referer information (e.g., network.http.sendRefererHeader=0), these attacks obviously do nothing.

The attack will fail if the user forcibly kills the browser, turns off her machine or severs her Internet connection before dismissing the dialog box.

The examples use dynamically generated iframe for demonstration purposes. These attacks work equally as well for static pages or top level content (e.g., sample using meta refresh [source]). Unfortunately, it is not as stealthy.

The meta refresh approach is most desirable, because the initial request is submitted without any referer information making the attack more difficult to detect.

These examples use intentionally goofy text. A real attack would use more appropriate text.

Invoking the "Joke Method" twice in a row crashes MineField/3.0a9pre.

Demonstration