Closed Bug 298255 Opened 19 years ago Closed 19 years ago

Stand-alone applications can run arbitrary code through Firefox

Categories

(Core :: Security, defect)

defect
Not set
critical

Tracking

()

RESOLVED FIXED

People

(Reporter: mikx, Assigned: dveditz)

References

(Depends on 1 open bug)

Details

(Keywords: fixed-aviary1.0.5, Whiteboard: [sg:fix] Bug details embargoed until August 1, 2005)

Attachments

(4 files, 1 obsolete file)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4

Most media types that can be viewed in Firefox using an embedded plugin, can
also be viewed in a stand-alone application. This applies to the most common
audio/video media types like ram/rpm/wmv/mov/avi, document formats like pdf and
multimedia formats like swf (flash). 

The stand-alone programms can (as every other desktop application) open URLs in
Firefox, usually be passing the URL to the operation system and invoking the
standard browser. The URL calls are (unlike when embedded) not checked at all. A
stand-alone mediaplayer can open chrome: and javascript: urls.

While this is expected behavior, it turns into a security risk when looking at
the fact, that it is easy to force that a media file gets opened in the stand
alone programm instead of embedding it. Usually it is enough to set
Content-Disposition header to type "attachement". This will result in a file
download dialog which most people will accept, since many websites use this as a
valid feature (e.g. for pdf downloads). Some video players (e.g. Quicktime)
support dedicated formats to force that a video gets played in the stand-alone
player - mostly due the fact that only the stand-alone quicktime player supports
real fullscreen playback. 

The problem is, that many media container formats (e.g. smil) and most
multimedia formats (e.g. swf) allow to automaticly open URLs by several
scripting languages or other mechanisms. That means scripting commands coming
from an untrusted source can automaticly invoke a desktop programm and then
re-invoke Firefox to run arbitrary code by opening a chrome: url and then a
javascript: url (to get universal xpconnect). 

One could argue, that this is a problem of the media players, but the media
players are (usually) secure in handling the various containers formats - they
just assume it is safe to throw urls of any kind at the default operation system
webbrowser. And in case of Firefox, it's not.

To proof this theory, i looked at the various file formats and players. I found
a reproducable way in the handling of stand-alone flash (swf) files. The
following peace of action script could be used to run arbitrary code from an swf
file in a stand alone player:

SWFAction("a=this.geturl('chrome://browser/content/browser.xul');b=this.geturl('javascript:alert(document.location);');"));

There are some timing issues with this demo (when the xul page loads too slow)
you usally have to try 2-3 times and re-start the browser after each try. I am
not so good in flash, there are probably ways to make that more stable. The good
news is, that flash does not ship with a stand-alone player by default, it only
comes with the flash development environment or from third partys. Anyway, bad
news is that it proofs the theory.

Another proven way to open a chrome url is the quicktime player (using <a href>
in a smil file) - and since the number of ways to manually and automaticly open
URLs from media formats are literally endless (real, windows media, quicktime
all support multiple ways of 'in-stream' url encodings, smil supports timed
hyperlink events, acrobat reader supports javascript, etc) i strongly believe
that there are many more ways.

Is there any valid use for desktop applications invoking a chrome file and/or
opening a javascript url in the context of another website? Shouldn't it be safe
to throw URLs at Firefox in any order - especially when considering that many
third party developers don't know about privileged xul? 

Reproducible: Always
It seems nobody takes care of this right now - still unconfirmed after a week.

I added a test case that shows an automated exploit of this bug. As described in
my initial post formats like QuickTime can automaticly open the stand-alone
player from within an embedded browser - it only requires a special target
property called "quicktimeplayer". The QuickTime player can run SWF files and
those can open chrome: and javascript: urls. Putting all this together you get a
fully running exploit.

The demo still has some timing issues, but should work properly in about 40% of
the attempts. Tried that on three different machines. Restart the browser and
close Quicktime after a failed attempt.

Raising the severity to critical since it's now fully working remote code execution.
Severity: normal → critical
Status: UNCONFIRMED → NEW
Component: General → Security
Ever confirmed: true
Flags: blocking1.8b3+
Flags: blocking-aviary1.0.5+
Product: Firefox → Core
Whiteboard: [sg:fix]
Version: unspecified → Trunk
This is doing something other than the normal opening a URL from an external
application. When opened from the OS each URL is going to get a new window (or
tab depending on pref settings), and in that situation the context for
javascript urls will be the harmless about:blank rather than the previous chrome
url.

This testcase demonstrates that's not the case. Are these URLs opened through
the plugin interface? I thought bug 280664 stopped the loading of chrome: from
plugins?
(In reply to comment #3)
> This is doing something other than the normal opening a URL from an external
> application. When opened from the OS each URL is going to get a new window (or
> tab depending on pref settings)

Not every time. Using flash you can open two urls more or less at the same
moment and that results in opening them in the same browser window (maybe just a
timing issue). Other browser (e.g. IE) do open two new windows.

Some other applications are at least able to open one url in an exesting window
- usually the currently active window/tab - this would lead to cross domain
scripting (e.g. to steal cookies):

1. Open the stand-alone quicktime player
2. Do a javascript location.replace to "target.domain" in the opening page
3. Invoke the existing window with a javascript: url in the context of
"target.domain"

This seems to be a window naming thing (e.g. it works when clicking a link in an
external application which targets "_parent"). It only works the first time.
After that you always open new windows unless you restart the browser.

> This testcase demonstrates that's not the case. Are these URLs opened through
> the plugin interface? I thought bug 280664 stopped the loading of chrome: from
> plugins?

When you play the SWF file in an embedded player, the patch for 280664 kicks in.
But in this case the OpenURL commands comes from the stand-alone player /
operation system and circumvents it.
(In reply to comment #3)
> This is doing something other than the normal opening a URL from an external
> application. When opened from the OS each URL is going to get a new window
> (or tab depending on pref settings)

True for the trunk: the pref browser.link.open_external is set to 3 in Firefox
(new tab) and 2 in Suite (new window). But on the aviary/1.7 branches it was set
to 1 -- reuse the currently open window.

I always seem to get the JS url to open first so I don't quite see the exploit,
but I imagine it would be trivial to put a delay in the flash script to make
sure the chrome URL has opened first. In any case a javascript URL could be used
to steal information from the currently opened page.

What if we do something like the solution to the history.back() bug and
explicitly load about:blank first to clear the plate when loading an external URL?
Whiteboard: [sg:fix] → [sg:fix] [cb] eta?
Assignee: nobody → mikx
In addition to putting a context-clearing about:blank load in front of any
javascript: or data: url, there's no need to allow chrome: urls to be loaded
into a browser window from external programs at all. People who have built
non-browser chrome applications launch them with "-chrome
chrome:/mychrome/content/", not "-url chrome:/mychrome/content/"
Yeah, sounds reasonable to me. Should be pretty easy to do, even. You hacking on
this dveditz?
Assignee: mikx → dveditz
This is a Suite issue as well.
Flags: blocking1.7.9+
Attached patch aviary 1.0.x patch (obsolete) — Splinter Review
This works for aviary.
Attachment #188417 - Flags: superreview?(jst)
Attachment #188417 - Flags: review?(mconnor)
Attachment #188417 - Attachment is obsolete: true
Attachment #188423 - Flags: superreview?(jst)
Attachment #188423 - Flags: review?(mconnor)
Attachment #188423 - Flags: approval1.7.9?
Attachment #188423 - Flags: approval-aviary1.0.5?
Comment on attachment 188423 [details] [diff] [review]
incorporating mconnor's suggestions

>+  try {
>+    if (makeURL(uriToLoad).schemeIs("chrome")) {
>+      dump("Preventing external load of chrome: URI\n");

lets go a step farther and add "To load chrome URIs, you must use the -chrome
switch.\n" here

>-                     .loadURI(url, nsIWebNavigation.LOAD_FLAGS_NONE, referrer,
>+                     .loadURI(url, loadflags, referrer,
>                               null, null);

nit: there's no need for the args to be split onto two lines now, you fixed
this in the previous case

>+    // Before going any further vet loads initiated by external programs.
>+    if (aLoadType == LOAD_NORMAL_EXTERNAL) {
>+        // clear the decks to prevent context bleed-through (bug 298255)
>+        rv = CreateAboutBlankContentViewer();

shouldn't you be checking rv here?

>+        // Disallow external chrome: loads targetted at content windows
>+        PRBool isChrome = PR_FALSE;
>+        if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
>+            return NS_ERROR_FAILURE;
>+        }

this should probably go before the previous block, since there's no point in
creating the new content viewer if we're going to fail here

r=me with those
Attachment #188423 - Flags: review?(mconnor) → review+
Attachment #188417 - Flags: superreview?(jst)
Attachment #188417 - Flags: review?(mconnor)
Comment on attachment 188423 [details] [diff] [review]
incorporating mconnor's suggestions

sr=jst
Attachment #188423 - Flags: superreview?(jst) → superreview+
Comment on attachment 188423 [details] [diff] [review]
incorporating mconnor's suggestions

a=chofmann for the branches
Attachment #188423 - Flags: approval1.7.9?
Attachment #188423 - Flags: approval1.7.9+
Attachment #188423 - Flags: approval-aviary1.0.5?
Attachment #188423 - Flags: approval-aviary1.0.5+
Whiteboard: [sg:fix] [cb] eta? → [sg:fix] [cb] patch ready to land
Landed on aviary branch
Whiteboard: [sg:fix] [cb] patch ready to land → [sg:fix] need 1.7 branch and trunk
Seeking Neil's r= on the navigator.js portion which was not reviewed as part of
the aviary branch patch
Attachment #188483 - Flags: superreview+
Attachment #188483 - Flags: review?(neil.parkwaycc.co.uk)
Attachment #188483 - Flags: approval1.8b3+
v.fixed on aviary with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.9)
Gecko/20050706 Firefox/1.0.5.

Still waiting to land on the Trunk and 1.7 branch, where it will need to be
verified as well.
Comment on attachment 188483 [details] [diff] [review]
trunk version (incl suite)

r=mconnor
Attachment #188483 - Flags: review?(neil.parkwaycc.co.uk) → review+
Not quite sure what to do about mozilla 1.7.x. This fix builds on the
nsIBrowserDOMWindow::OPEN_EXTERNAL stuff that was added to aviary but not the
suite until sometime on the trunk.
Fix checked into trunk. Neil has some concerns that this blocks the ability to
have a chrome: home page and is working on an alternate patch for the "startup"
part of this.

That approach will also work for the 1.7 branch to prevent loading chrome urls
from external, but not solve the javascript: problem unless we're ok just
blocking those outright.
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Whiteboard: [sg:fix] need 1.7 branch and trunk → [sg:fix] need 1.7 branch
+    if (makeURL(uriToLoad).schemeIs("chrome")) {

is that sufficient? For example, about:config also has chrome privileges. is
that taken care of by the other checks?
Actually it turns out that suite already (tries to, but my Windows doesn't
recognise it) associate external chrome: URLs with the -chrome option.
Group: security
Blocks: 299444
Blocks: 300114
Group: security
Adding distributors
Suite 1.7 is OK on this one: the default behavior is to open external links in
new windows so javascript: urls are always run in an about:blank context. The
trunk version of the suite has the option to reuse the most recent window (still
not the default), but the context-clearing fix landed on the trunk.
Whiteboard: [sg:fix] need 1.7 branch → [sg:fix] Bug details embargoed until July 20, 2005
Filed bug 300800 on some issues I think that patch has...
Depends on: 300800
Looks like the fix to this bug caused bug 301073.

/be
Comment on attachment 188483 [details] [diff] [review]
trunk version (incl suite)

Mozilla/Suite uses -chrome for chrome:// URL protocol so I claim it doesn't
need the startup patch so please back it out to fix the xpfe version of bug
301073.
Whiteboard: [sg:fix] Bug details embargoed until July 20, 2005 → [sg:fix] Bug details embargoed until August 1, 2005
Group: security
More followups: bug 305374, bug 305269, bug 304690.
Flags: testcase+
Depends on: 310793
Flags: in-testsuite+ → in-testsuite?
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: