Last Comment Bug 616659 - (CVE-2011-0051) Recursing the JavaScript eval function over itself eventually causes all dialogs with confirmation to evaluate to "true".
(CVE-2011-0051)
: Recursing the JavaScript eval function over itself eventually causes all dial...
Status: RESOLVED FIXED
[sg:critical] [qa-ntd-191]
: verified1.9.1, verified1.9.2
Product: Core
Classification: Components
Component: DOM: Core & HTML (show other bugs)
: unspecified
: All All
: -- critical (vote)
: ---
Assigned To: Olli Pettay [:smaug] (reviewing overload)
:
:
Mentors:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2010-12-03 21:38 PST by Zach Hoffman
Modified: 2014-09-04 09:39 PDT (History)
14 users (show)
rforbes: sec‑bounty+
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---
betaN+
.14+
.14-fixed
.17+
.17-fixed


Attachments
fix? (854 bytes, patch)
2010-12-08 09:55 PST, Olli Pettay [:smaug] (reviewing overload)
jst: review+
Details | Diff | Splinter Review
v2 (989 bytes, patch)
2010-12-16 08:39 PST, Olli Pettay [:smaug] (reviewing overload)
dolske: review+
gavin.sharp: review+
christian: approval1.9.2.14+
christian: approval1.9.1.17+
Details | Diff | Splinter Review

Description Zach Hoffman 2010-12-03 21:38:34 PST
User-Agent:       Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5
Build Identifier: http://www.mozilla.com/en-US/products/download.html?product=firefox-3.6.12&os=win&lang=en-US

Obviously, code like eval(a="eval(a)") causes the script to error out.  But adding a try/catch block like eval(a="try{eval(a)}catch(b){/*code here*/}") lets you catch the "eval'd-out" state and execute code in it.  Any dialog box opened in this state instead shows a textless dialog box with two textless buttons, and pressing these buttons does not close this box.  Closing the box with the corner "X" button causes input boxes (confirm, onbeforeunload, netscape.security.PrivilegeManager.enablePrivilege, etc.) to evaluate to "true".

Reproducible: Always

Steps to Reproduce:
The following code will open a dialog: eval(a="try{eval(a)}catch(b){c=confirm('You will not see this text')}")
Actual Results:  
In Windows 7, the only immediate way to close the aforementioned dialog is by pressing the "X" corner button.  If the user performs this action, Firefox will proceed as if the user pressed "OK", causing c == true.

Expected Results:  
In a normal case, this action is the equivalent of pressing "Cancel", meaning c == false.

See the attachment in the comments for an example that uses this vulnerability for arbitrary code execution.
Comment 1 Zach Hoffman 2010-12-03 21:48:01 PST
Created attachment 495216 [details]
On Windows systems, clicking the button causes a textless dialog to pop up.  "X"-ing out the dialog opens C:\WINDOWS\system32\calc.exe.

Because this example uses netscape.security.PrivilegeManager.enablePrivilege, an on-the-Web version would be just as dangerous but would probably need to be placed inside a signed script JAR.  To avoid this complexity, I'm assuming that you know to run it locally.
Comment 2 Zach Hoffman 2010-12-04 01:35:28 PST
Created attachment 495224 [details]
Same example, except the routine ends after calc.exe is opened only once (less annoyance).

As before, run locally on Windows.  Clicking the button causes a textless dialog to pop up. "X"-ing out the dialog opens C:\WINDOWS\system32\calc.exe.
Comment 3 Daniel Veditz [:dveditz] 2010-12-06 14:04:00 PST
Awesome.

Assigning to Olli per jst.
Comment 4 Daniel Veditz [:dveditz] 2010-12-06 14:22:15 PST
On Mac we use "sheets" rather than dialogs -- there is no 'X' to dismiss. You end up unable to switch tabs or do much of anything and must force-quit (arguably better than letting the attack succeed). I expect the attack to succeed on Linux but have not tried it (of course the testcase must be modified).

I tried Minefield on windows and did not get the testcase to work. The dialog never came up and eventually I got a security exception about file:/// trying to get UniversalXPConnect privs. I don't think we changed anything with enablePrivilege so maybe we changed something in the JS engine or DOM that causes the attack to fail (the dialogs return false/cancel when they can't be created?). The attack definitely succeeds on Windows in both 3.5.x and 3.6.x
Comment 6 Olli Pettay [:smaug] (reviewing overload) 2010-12-08 04:47:04 PST
On 3.6 linux the browser just enters to an endless loop 
and gives "JavaScript error: , line 0: too much recursion"
There are no dialogs.
Comment 7 Olli Pettay [:smaug] (reviewing overload) 2010-12-08 08:39:45 PST
So how do I get the "sheet" on OSX?
I run the test locally, and still just get endless loop or something.
No dialogs, no "sheets".
Comment 8 Brandon Sterne (:bsterne) 2010-12-08 08:54:36 PST
When I ran the testcase on OSX I saw just the very beginning of the "sheet" which was just a square a few pixels wide right below the location bar.  It was window-modal, though, in the sense that my menus were disabled and I couldn't switch to any other tab.
Comment 9 Olli Pettay [:smaug] (reviewing overload) 2010-12-08 09:22:34 PST
Ah, ok. I think I see something similar on OSX.
Comment 10 Olli Pettay [:smaug] (reviewing overload) 2010-12-08 09:55:28 PST
Created attachment 496170 [details] [diff] [review]
fix?

I don't have Windows development setup, and can't reproduce the problem on Linux
and on OSX the problem is not critical if I understand this right.

But here is a patch which might help.
Based on the code and the error I get on Linux this could help.
Anyone willing to try? The fix is for netscape.security.PrivilegeManager.enablePrivilege() -like prompts.
Comment 11 Olli Pettay [:smaug] (reviewing overload) 2010-12-15 15:58:15 PST
Comment on attachment 496170 [details] [diff] [review]
fix?

OK, this fixes the critical part of the bug.
Similar thing could be added to other dialogs.
Comment 12 Olli Pettay [:smaug] (reviewing overload) 2010-12-15 16:27:09 PST
(In reply to comment #4)

> I tried Minefield on windows and did not get the testcase to work. The dialog
> never came up and eventually I got a security exception about file:/// trying
> to get UniversalXPConnect privs. I don't think we changed anything with
> enablePrivilege so maybe we changed something in the JS engine or DOM that
> causes the attack to fail (the dialogs return false/cancel when they can't be
> created?). The attack definitely succeeds on Windows in both 3.5.x and 3.6.x
Prompt handling was rewritten for FF4.
Comment 13 Olli Pettay [:smaug] (reviewing overload) 2010-12-15 16:29:18 PST
So I could still clarify that the code where the bug is, has been removed in FF4.
Comment 14 Justin Dolske [:Dolske] 2010-12-15 17:01:21 PST
What exactly is the patch fixing? eButtonPressed isn't checked by other code, and commonDialog.js's commonDialogOnload() should be initializing it already... Is this bug somehow causing a code path that avoids the initialization?
Comment 15 Blake Kaplan (:mrbkap) 2010-12-15 17:15:07 PST
(In reply to comment #14)
> What exactly is the patch fixing? eButtonPressed isn't checked by other code,
> and commonDialog.js's commonDialogOnload() should be initializing it already...
> Is this bug somehow causing a code path that avoids the initialization?

By the time that we try to call into commonDialog.js, we're already basically out of C stack space to run JS in, so we probably throw trying to even call into that code. However, given what a mess all of the dialog/window code is, we probably lose the fact that we failed to run the JS somewhere and continue on as if we had.
Comment 16 Justin Dolske [:Dolske] 2010-12-15 21:12:04 PST
Ah, I guess that makes sense. Mildly surprising there isn't an error being returned back from OpenWindow(), we still use that code path so it would kinda be nice to figure out where the fail is being dropped.

But this workaround seems fine. You could fix all the prompts for free by having nsPromptService::DoDialog() just do aParamBlock->SetInt(eButtonPressed, 1). Unconditionally setting this should be fine. [IE, basically do the initialization commonDialog.js was doing.]
Comment 17 Blake Kaplan (:mrbkap) 2010-12-16 00:43:11 PST
(In reply to comment #16)
> Ah, I guess that makes sense. Mildly surprising there isn't an error being
> returned back from OpenWindow(), we still use that code path so it would kinda
> be nice to figure out where the fail is being dropped.

This is total speculation, but I assume that we run JS while loading the XUL for the dialog's window. That would mean that the error actually gets thrown into a nested event loop run by nsWindowWatcher::OpenWindowJSInternal and gets lost there.
Comment 18 Olli Pettay [:smaug] (reviewing overload) 2010-12-16 08:27:06 PST
(In reply to comment #16)
> You could fix all the prompts for free by
> having nsPromptService::DoDialog() just do aParamBlock->SetInt(eButtonPressed,
> 1). Unconditionally setting this should be fine. [IE, basically do the
> initialization commonDialog.js was doing.]
Yeah, could probably do that.
Comment 19 Olli Pettay [:smaug] (reviewing overload) 2010-12-16 08:39:50 PST
Created attachment 498119 [details] [diff] [review]
v2
Comment 20 Olli Pettay [:smaug] (reviewing overload) 2010-12-27 00:29:42 PST
Dolske, review ping.
Comment 21 christian 2010-12-27 10:25:38 PST
Waiting on review to approve.
Comment 22 :Gavin Sharp [email: gavin@gavinsharp.com] 2010-12-27 11:24:14 PST
Comment on attachment 498119 [details] [diff] [review]
v2

Would be good to add a "Default to 'Cancel'" comment.
Comment 23 Olli Pettay [:smaug] (reviewing overload) 2010-12-27 11:32:44 PST
Sure. I'll add that before pushing.
Comment 24 christian 2010-12-29 10:15:40 PST
Comment on attachment 498119 [details] [diff] [review]
v2

Approved for 1.9.2.14 and 1.9.1.17
Comment 26 Al Billings [:abillings] 2011-01-04 14:02:21 PST
I don't think that I'd call this fixed. I verified the problem with 1.9.2.13 and then tried the nightly .14pre build on XP. The PoC's no longer launch calculator after the fix but the browser is still completely unusable. The user winds up with an Internet Security dialog with two blank buttons that cannot be closed. See http://img84.imageshack.us/img84/8548/screenshot20110104at153.png.

The only way out is to kill the entire Firefox process. Does a DoS count as fixed? :-)

Loading both of the PoC's on 1.9.1.16, as soon as the user clicks on the "clicky" button, the whole browser loses focus and cannot be closed (I can't see focus going anywhere but the main window cannot get it back). The only solution is to kill the process. No calculator is launched but the browser is unusable. Post-fix on 1.9.1.17pre, the behavior is exactly the same.

This appears to need some more work.
Comment 27 Olli Pettay [:smaug] (reviewing overload) 2011-01-04 14:27:45 PST
I was fixing the sg:critical part of the bug. The DoS part is something quite different.
Comment 28 Al Billings [:abillings] 2011-01-04 14:37:56 PST
So I can call this "verified" for 1.9.2 since calculator doesn't launch?

Pre-fix on 1.9.1, it never launches calculator and the pre and post-fix behavior is the same. I'm not sure what to verify there.
Comment 29 chris hofmann 2011-01-04 15:13:05 PST
> So I can call this "verified" for 1.9.2 since calculator doesn't launch?

that sounds right once you get to a state like Dan had in comment 4 where he was able to recreate on 1.9.1 and 2.

and maybe open a new bug for the sg:dos part?
Comment 30 Al Billings [:abillings] 2011-01-04 15:33:36 PST
I haven't been able to duplicate Dan's state in comment 4. Dan, any comments or suggestions? Have you been able to duplicate it again?
Comment 31 Johnny Stenback (:jst, jst@mozilla.com) 2011-01-04 18:49:28 PST
What exactly is left here for trunk?
Comment 32 Olli Pettay [:smaug] (reviewing overload) 2011-01-05 01:53:47 PST
The code where the sg:crit bug is, has been removed in the trunk.
Comment 33 Olli Pettay [:smaug] (reviewing overload) 2011-01-05 01:55:27 PST
Gavin, why did you change this to UNCONFIRMED? And removed also 1.9.1 and 1.9.2 status flags?
Comment 34 Olli Pettay [:smaug] (reviewing overload) 2011-01-05 01:56:59 PST
Changing back to fixed.
Comment 35 :Gavin Sharp [email: gavin@gavinsharp.com] 2011-01-05 11:04:24 PST
Sorry, just a mistake (didn't reload hard enough).
Comment 36 Al Billings [:abillings] 2011-01-06 16:47:46 PST
Marking verified for 1.9.2. Since the problem doesn't manifest with the PoC on 1.9.1, I can't verify the fix there.
Comment 37 Zach Hoffman 2011-01-07 02:04:06 PST
Created attachment 501952 [details]
Testcase 3

Apparently, in 1.9.1 the browser's behavior varies depending on whether any dialogs have been shown during the current session but prior to the attack.  This example displays a dialog before continuing, which probably causes it to succeed for the entire 1.9.1 branch.
Comment 38 Al Billings [:abillings] 2011-01-18 17:30:42 PST
Using the new testcase 3, I've verified calculator launching pre-fix and being fixed in the current 1.9.1 nightly (Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.17pre) Gecko/20110118 Shiretoko/3.5.17pre ( .NET CLR 3.5.30729)).

Note You need to log in before you can comment on or make changes to this bug.