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.

Published Monday, July 23, 2007 10:51 PM by Alun Jones

Comments

# Window Snyder fesses up - Firefox also passes "bad data"

Window says: "Over the weekend, we learned about a new scenario that identifies ways that Firefox

Tuesday, July 24, 2007 2:09 AM by Spyware Sucks

# University Update-Microsoft Visual Studio-FirefoxURL - potshots part deux

Pingback from  University Update-Microsoft Visual Studio-FirefoxURL - potshots part deux

# re: FirefoxURL - potshots part deux

re: "You can't comment in an unbiased fashion, because you're a Microsoft MVP."

Window and Asa are Mozilla employees who have been *very* biased in their public commentary during this brouhaha - I'm gobsmacked that a FF supporter would have the balls to make such a statement about Alun.  It is sad to see how recent events have have brought out the worst in FF supporters.  

It worries me that FF are barrelling down a dangerous highway to try and "fix" a problem that isn't theirs to fix.  Do they *really* want to start down the slippery slope of taking responsibility for validating data on behalf of who knows how many third party applications? How are they going to that? What will they break?

I can only hope that Window, Asa et al will sit down and think things through properly.

Tuesday, July 24, 2007 8:49 AM by sandi

# re: FirefoxURL - potshots part deux

That comment about MVP status being an indication of bias was actually made in a personal exchange, and to the extent that the speaker intended it, it's true - my MVP status suggests (but doesn't require) that I know more about Microsoft solutions than about non-Microsoft solutions.

But you don't have to look far to find Microsoft MVPs who spend most of their time in a non-Microsoft field (Steve Friedl of http://unixwiz.net/ is my favourite example).

Tuesday, July 24, 2007 10:17 AM by Alun Jones

# re: FirefoxURL - potshots part deux

Firstly: STD 66 absolutely does require that quote marks be percent-encoded.  Any URI with unencoded quote marks is illegal.  I quite agree that IE shouldn't encode quote marks appearing in a URI; but it should reject the URI as illegal and refuse to do anything with it, least of all pass it to third party software.

However: according to Microsoft's documentation, the URI is decoded before being passed to the protocol handler.  For instance, if the URI contains %20 that will be replaced by a space.

This has several implications.  Firstly, it means that the original vulnerability can probably be exploited with *legal* URIs; encoded quotes will be decoded before being passed to the protocol handler.

Secondly, it means that Firefox probably needs to re-encode the entire URI to have the best shot of getting it to the form it should be in.

I notice you say that the URI should only be encoded by the party creating it and only decoded by the party processing it.  I quite agree, and consider that to be Microsoft's fundamental mistake here; the protocol handler specification should not require that the URI be transmitted in decoded form but that it be transmitted unmodified - provided, of course, that it is legal. :-)

Tuesday, July 24, 2007 10:59 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

STD66 is another name for RFC 3986, and it says: "Under normal circumstances, the only time when octets within a URI are percent-encoded is during the process of producing the URI from its component parts."

Since IE is not producing the URI from its component parts, I presume you are saying that acting as a proxy between a producer and a consumer of a URI is outside of "normal circumstances" - is that right?

As you note, Microsoft does decode percent-encoded values on their way to the protocol handler, and I view that as incorrect behaviour under the standard - my next part of this series will be to document some of the things I see Microsoft doing when it calls protocol handlers that I think are incorrect, though not a security flaw in themselves.

I have not seen any discussion by the Mozilla folks as to how they intend to avoid the double-encoding / single-encoding confusion that may follow from their change - but of course all protocol handlers will have to add extra work to handle this from now on - is the URI from IE, and therefore already decoded, or is it from Firefox, and therefore needs decoding?

Either way, you still need to act like the only thing you can trust is that "the entire remainder of the command line" comes from the user and cannot be trusted.

Wednesday, July 25, 2007 11:14 AM by Alun Jones

# re: FirefoxURL - potshots part deux

STD66/RFC3986 restricts the characters that can legally appear in a URI without being encoded.  I agree that the encoding should be done by the party generating the URI not by an intermediary; however I would argue that the intermediary is entitled (in fact obliged) to reject a URI that has not been properly encoded by the originating party.

In other words, I suggest that if a web browser encounters a link containing illegal characters (including spaces and double quote marks that haven't been percent-encoded) it should refuse to attempt to follow it.

Wednesday, July 25, 2007 7:07 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

Hmm... that would kind of kill

javascript : alert("Hello world")
, wouldn't it?

I wonder if there are any other things that look like URIs and have bad characters in them?

Why can't the intermediary simply pass everything on, like the proxy that it's pretending to be, and expect the protocol handlers to behave like the secure Internet-facing applications that they are pretending to be?

Wednesday, July 25, 2007 8:10 PM by Alun Jones

# re: FirefoxURL - potshots part deux

I don't think Javascript really counts as a URI; I mean, it doesn't identify a resource, does it?

I'd love it if all the protocol handlers would cope with illegal data properly, but the reality is that dozens of handlers have been identified that all made the same mistake, and I'm not aware of a single one that got it right; OK, I haven't actually looked, but you get my drift.  :-)

I don't think it's realistic to expect that everybody will fix this problem promptly and that no newly written software is going to reproduce it.  At the end of the day I don't really care who is to blame, but I don't want to be vulnerable; at the moment, it looks like the only way to avoid it is going to be to avoid IE.

Thursday, July 26, 2007 8:59 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

Yes, the 'javascript' line was a bit facetious of me - but it makes the point that there's plenty of "URI"-looking links that disobey RFC 3986, and it's not too much of a stretch to think that protocol handlers might expect to do the same.

I haven't seen the 'dozens of handlers' that you've heard of, which have exploitable vulnerabilities. I've seen one class of handlers - basically, everything that Mozilla ever wrote.

Looking at the source code, they receive the single LPSTR command line argument in the WinMain function ... and then they discard it, and use an undocumented(!) pair of global variables to pass arguments into a main() function.

Almost seems as if it was written by a Unix programmer who didn't feel at home in Windows. :)

The flaw is definitely in the handler - fix it in the handler, and it doesn't matter which browser you use.

Obviously we're not going to agree here - to my mind, Internet Explorer is designed to behave like a transport mechanism here - you might as well ask that this be fixed in the TCP stack.

To you, the browser should have intimate understanding and be allowed to muck with URIs without any requirement to understand them, on what I perceive as a rather flimsy stretching of RFC 3986.

Our positions are irreconcilable - but the discussion is worth having.

Thursday, July 26, 2007 9:44 PM by Alun Jones

# re: FirefoxURL - potshots part deux

Have a look here:

bugzilla.mozilla.org/attachment.cgi

I'm not saying all of these are actually exploitable but a lot of them obviously assume there won't be quotes (or in some cases command-line switches) in the incoming data.

Thursday, July 26, 2007 9:57 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

You draw a conclusion that isn't necessarily true.

Using "%1" instead of %1 is as much a habit as a programming practice designed to catch arguments with spaces.

However, anyone who puts a command-line argument after the user-supplied argument is suggesting poor judgement, even though that, too, could be handled by counting backward from the end of the string.

Were I to review these protocol handlers for security issues, I'd start first with those that end with an argument after the %1; then I'd go to those with undocumented arguments, such as %L. That way I'd be attacking the handlers with the most likelihood of being unsecure.

However, as you point to the ones with "%1" as being likely vulnerable to unencoded quotes, you should also point to those with %1 as being likely vulnerable to spaces.

Thursday, July 26, 2007 11:20 PM by Alun Jones

# re: FirefoxURL - potshots part deux

Yeah, I guess it's pretty subjective, and I may be overestimating how many are actually risky.

For what it's worth, I'd personally expect a safe handler to look something like this:

someexecutable /handler %1

That would be straightforward to code.  Putting quotes around the %1 doesn't achieve anything except forcing you to add the code to remove them.

Even simpler would be

someexecutable %1

but only if there aren't any possible flags to look for.

In either case, of course, the code might or might not be doing the right thing; the only way to tell is to look at the code or try to break it.

Friday, July 27, 2007 2:10 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

You wrote: "To you, the browser should have intimate understanding and be allowed to muck with URIs without any requirement to understand them, on what I perceive as a rather flimsy stretching of RFC 3986."

I hate to drag on a discussion that's probably starting to get tedious, but ... well, I'm going to anyway. :-)

In case it wasn't clear, I don't want the browser to "muck with" URIs; just to validate them against the syntax defined by the RFC, at least so far as to check that they contain only valid characters (this is trivial to do).

I'll grant that so far as I know there is no documented standard for what a browser or other intermediary should do when faced with an illegal URI, but I think it's accepted practice in computing that a program can do anything it thinks best with illegal data.  This might mean stopping dead, ignoring it, trying to turn it into legal data, or processing it exactly as if it were legal.

I recall Microsoft producing some software to sit in front of IIS and block potentially dangerous requests; I imagine this included any request whose URL contained illegal characters.  The analogy isn't perfect, but you agree that in at least some cases it is OK for an intermediary to block data known to violate the relevant syntax?

Friday, July 27, 2007 5:50 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

If the intermediary is knowledgable of the behaviour of all the handlers underneath it, yes. Otherwise, you move the support burden from people whose software is vulnerable, to people whose software may or may not be vulnerable, but which used a feature of the lack of encoding.

Friday, July 27, 2007 8:06 PM by Alun Jones

# re: FirefoxURL - potshots part deux

As an unbiased Windows C++ programmer, here are my $.02:

The problem here is that the winapi uses a string for CreateProcess and WinMain instead of an array of strings and leaves it up to the program to mess with the command line (including wildcard expansion!).

The problem is compounded by the fact ShellExecute function that takes a format string and a parameter string and just blindly substitutes parameters.

So yeah, I definitely blame Microsoft for creating this nightmare that every application now has to deal with because they took the lazy approach (IMNSHO).

Given the above, the only correct way for firefox to proceed is:

1. Change their url handler to something like "c:\blah\firefox.exe" /unsafeurl:%1 and then use GetCommandLine() to look for everything after /unsafeurl:

2. Speaking of which, why did the register firefoxurl to begin with?

3. Not do something extremely idiotic like writing their own ShellExecute function as bugzilla.mozilla.org/show_bug.cgi suggests that parses the registry values and calls the url handlers in a way that's friendly to parse_cmdline().

And thinking out loud here, somebody should investigate how ShellExecute and CreateProcess handle going over the ~32k (I think) command line string limit.

Sunday, July 29, 2007 2:30 AM by asdf

# re: FirefoxURL - potshots part deux

"The problem here is that the winapi uses a string for CreateProcess and WinMain instead of an array of strings and leaves it up to the program to mess with the command line (including wildcard expansion!)."

My thought is that this is actually behaviour that you want for a protocol handler, because the URI is a single string, and might not follow the same parsing as shell commands.

If you want shell command style parsing, you can get that by calling CommandLineToArgvW, but given that spaces and tabs might be special to the URI but are not differentiated in Argv-based parsing, I don't see that argv processing gives you anything in a protocol handler.

"The problem is compounded by the fact ShellExecute function that takes a format string and a parameter string and just blindly substitutes parameters."

What else should it do?

As for ShellExecute and long command lines, ShellExecute is documented as returning an error code when the command line is over (INTERNET_MAX_URL_LENGTH - 1) characters. CreateProcess is limited to 32k.

Sunday, July 29, 2007 7:48 PM by Alun Jones

# re: FirefoxURL - potshots part deux

"My thought is that this is actually behaviour that you want for a protocol handler, because the URI is a single string, and might not follow the same parsing as shell commands."

Generally I prefer the single-string approach, I guess because I grew up with DOS/Windows rather than Unix/Linux.  But the Linux approach does have an advantage in this scenario, because the launching application passes an array rather than a string, so no parsing is necessary to separate out the arguments.

The Linux version of Firefox never had this vulnerability because the presence of quotes had no effect on the way arguments were separated.

Saturday, August 04, 2007 4:04 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

No, the Linux version of Firefox never had this vulnerability, because the arguments were passed from browser to protocol handler without going through the shell.

The Windows version of Firefox had the opportunity to create a protocol handler that could receive arguments from a browser without going through the shell, but chose to ask the shell to parse those arguments.

Sunday, August 05, 2007 4:04 PM by Alun Jones

# re: FirefoxURL - potshots part deux

("shell" = "C runtime library"?)

Well, it has to parse them somehow!

The point is that under Windows all you get is a single string, so you have to parse it to divide it up into separate arguments.  You can let the runtime library do it, or you can do it yourself; either way, you're potentially vulnerable if you haven't considered the possibility that one of the arguments might contain unexpected delimiters.

Under Linux the arguments are passed from the caller to the recipient as an array - already separated - so the presence of delimiters in an argument has no effect.

As a more extreme case, suppose for some reason you had to pass two arbitrary strings instead of one.  In Linux this would be easy.  In Windows the processes would have to agree on a quoting mechanism to cope with delimiters, or use some more complicated technique like DDE or COM.

I'm still more comfortable with the Windows approach; but I do think the Linux approach has some advantages.

Monday, August 06, 2007 3:52 PM by Harry Johnston

# re: FirefoxURL - potshots part deux

In this case, yes, the shell on Unix is the equivalent to what the C runtime library is doing. On Unix, command-line arguments are split by the shell, and you can sidestep this parsing by calling execp directly, passing in the array of arguments that should go to the executable. On Windows, that can't happen directly, because all executables take a single parameter. If you wanted the original "pass an array to be interpreted exactly as given", you could implement the protocol handler as a COM object. That is one of the documented approaches offered. The Mozilla team chose to do a Win32 app, and either didn't understand what they were giving up by making that choice, or didn't think it was important.

Tuesday, August 07, 2007 5:53 PM by Alun Jones

Leave a Comment

(required) 
(required) 
(optional)
(required)