FirefoxURL - potshots part deux
I've been encouraged to collect together some comments that I've made over on other people's blogs about the firefoxurl: vulnerability.
First, I do have to note with a little embarrassing schadenfreude that Mozilla's Window Snyder, Chief Security Something-or-other, has acknowledged that Firefox exhibits the same simple parameter passing mechanism as Internet Explorer (curiously without mentioning Jesper's discovery of it), and that they are researching what to do about this behaviour, which they view as a bug (note that this is a stark departure from her previous statement (the emphasis below is hers, not mine):
This patch for Firefox prevents Firefox from accepting bad data from Internet Explorer. It does not fix the critical vulnerability in Internet Explorer. Microsoft needs to patch Internet Explorer, but at last check, they were not planning to...
Mozilla recommends using Firefox to browse the web to prevent attackers from taking advantage of this vulnerability in Internet Explorer.
Embarrassing to have to recognise that "using Firefox to browse the web" does not "prevent attackers from taking advantage of this vulnerability", but that's something you learn - the more you poke holes in other people's software, the more you need to be looking for similar holes in your own - you should, at least, check to see that you don't have exactly the same hole. [Though, as I'll explain below, I don't think it's a hole.]
Now, to poke holes in some arguments:
- Claim: The RFCs require that some characters be percent-encoded.
Rebuttal: No, they don't.
At least, not from an intermediary. RFC 3986 specifically states that encoding should be performed once, by the party creating the URI, and decoding should be performed once, by the party processing the URI. This makes a lot of sense, as doubly-encoding and then singly-decoding, or vice-versa, is liable to lead to all manner of confusing results. Expect encoding at the URI creation point (but allow reasonable non-encoded URIs to pass through), and decode only when you're about to process the parts of the URIs - and don't mess with the URI's content if you don't natively host the protocol.
- Claim: Firefox prompts you with a dialog, so that's alright.
Rebuttal: Firefox prompts you the first time you activate a protocol handler, and offers you the opportunity to dismiss the dialog. So, the attacker can simply shoot off "firefoxurl:happy_place", in the anticipation that you'll approve the dialog, and then follow it up with "firefoxurl:nasty_stuff" because that will automatically be approved. The dialog tests only for the binary measure of "do I implicitly trust everything this protocol handler will do for any page I visit?" It's a convenience feature, not a security measure.
- Claim: This is a Windows bug, other operating systems would separate multiple arguments properly.
Rebuttal: No, they don't. Not even all Unixes do this.
Here's how I put it in one or two comments:
I've got to agree with Jesper here - IE laid down the parameter-passing method, and given that there's only one parameter ("the rest of the URL after the scheme and the colon"), there's not much point doing any quoting, encoding, or anything - as long as the end of the parameter is uniquely defined (and if not, what has the attacker done?) Remember, too, that the parameter parsing mechanism used here is going to be solely dependent on the language and API the protocol handler uses. It's only because most people use C / C++ / etc that we're used to seeing multiple arguments separated by spaces, tabs, etc. What the OS passes in to the executable is the entire command line from start to finish in one long string. Any other structure that you believe is present in the command line is imposed by the runtime library that the executable starts up before it calls the "main()" or other first developer-level function.
As it turns out, the shell does not handle quote characters in this case. It is the runtime library for the particular language which does.
If you choose C or C++ as your language of choice, for instance, the command line string as a whole is parsed in the CRT library routine parse_cmdline(), which (if you have Visual Studio installed) is in %ProgramFiles%\Microsoft Visual Studio 8\VC\crt\src\stdargv.c
If you use assembler, or write your program for Win32 (with a start function of WinMain instead of main), you'll be given the command line as a single string from first character entered to the final character provided by your caller.
Double-quote processing is a feature of C and C++, NOT of the Windows executable calling mechanism.
To put it another way, double quotes are only special to Firefox because Firefox's programmers chose to treat them specially. As such, it's their responsibility to ensure that they are handled correctly when faced with data provided by untrusted third parties.
If you want to see where the single-parameter command line gets split into multiple argv values that the C / C++ programmer might expect, in the Microsoft C Runtime Library (CRTL) it's in the file stdargv.c, routine parse_cmdline(). Any Visual Studio installation should have this file.
- Claim: Mozilla had no way of knowing that this was the way protocols would be passed to their handler.
Rebuttal: This is actually the way the protocol handler mechanism is documented. The entire URL is passed to the protocol handler as a replacement for the %1 parameter.
Claim: The assumption with commandline parameters is that they come from the user, and are thus fully trusted.
Rebuttal: This is not merely a command line - it is a declared and documented handoff of untrusted data coming from a remote and untrusted third party, not the OS, and not the user, but a potential hacker.
When Firefox registers 'firefox -url "%1"' as a protocol handler, their programmers have declared that they are aware that anything coming through in "%1" is untrusted and unfiltered data, potentially from a hacker. If they choose to fully trust that, then they are either asleep at the switch, or not aware of security concerns.
It's vital for the protocol handler to see the "-url" argument as indication that everything following it is suspect. The first double-quote should not be taken as a sign that "%1" is over - the last double-quote before the end of the command line is that indicator.
Claim: This is a bug in Internet Explorer and Firefox, and at least Mozilla is producing a fix for it.
Rebuttal: Okay, let's take a look at Mozilla's fix. They've added code to percent-encode double quotes, and after a little discussion, to also percent-encode spaces. Not a security-savvy way of addressing this problem - if you're going to start messing with that URL, then use the "known good" principle. [That means that, if you know that alphanumerics and a few symbols are 'good', and don't need to be encoded, then everything else should be encoded.]
It's also not, as I pointed out above, an RFC-compliant fix, because now the URI is doubly-encoded, and then singly-decoded. [Perhaps this is why the Mozilla team fixing this bug chose to only encode a couple of characters? To forestall possible backward compatibility issues?]
It's not minimally invasive, and it still doesn't address the issue that a protocol handler might be written by someone who forgot to think about the security implications of accepting third-party input. I've thought up dozens of ways in which you could write a dorky protocol handler that was open to attack, and none of them can be, or should be, addressed by the browser that calls them.
Claim: You can't comment in an unbiased fashion, because you're a Microsoft MVP.
Rebuttal: Can you not do any better than that? Seriously, attack the message, not the messenger. The MVP award is a retrospective award, given for the previous year's contributions to educating and assisting the community of Microsoft users. Since there is no published criteria, and what known criteria there is changes from year to year, it's useless to "try" and be an MVP, so I don't behave in any special way to continue my MVP-ness. I certainly don't kow-tow to Microsoft.
In summary, this isn't a bug - it works as designed and as documented, and the design does not carry with it any ability for bad behaviours that you shouldn't already be trying to handle anyway. Mozilla's previous statements have backed them into a corner where they feel they have to "fix" the bug. The mature thing to do would be to analyse whether they really have to change behaviour, or whether that change in behaviour is more likely to generate problems than solutions.
That's all I have time and energy for tonight - maybe there will be more soon.