Closed Bug 389580 (CVE-2007-4041) Opened 14 years ago Closed 14 years ago

some schemes with %00 launch unexpected handlers on windows


(Core Graveyard :: File Handling, defect)

Windows XP
Not set


(Not tracked)



(Reporter: dveditz, Assigned: Biesinger)




(Keywords: fixed1.8.1.6, verified1.8.0.13, verified1.8.1.8, Whiteboard: [sg:investigate])


(7 files, 3 obsolete files)

On Windows XP some urls for "web" protocols that contain %00 launch the wrong handler and appear to be able to launch local programs, with limited argument passing. It is not yet clear that this can be used to compromise a machine but we can always fear the worst.

The same behavior is observed using "Run" from the Windows Start menu for the affected protocols (http, https, ftp, gopher, telnet, mailto, news, snews, nttp, possibly others?).

The behavior seems to be that if there's a %00 in the URL for these schemes then the URL Protocol handler is not called, instead the FileType handler is called based on the extension of the full url. The url is then passed to that File handler. For "non-web" URL handlers the URL is passed to the expected handler.

In Firefox browser protocols are handled internally so are not vulnerable, but the mailnews protocols are handed off to the OS and can be abused in this way.

The fix in bug 389106 mitigates the published testcases but doesn't actually "fix" the problem.
Flags: blocking1.9?
Flags: blocking1.8.1.7+
Flags: blocking1.8.1.6+
Whiteboard: [sg:investigate]
Attached patch patchSplinter Review
don't load external URLs containing %00
Attachment #273843 - Flags: superreview?(dveditz)
Attachment #273843 - Flags: review?(bzbarsky)
Should we do anything about escaped newlines/carriage returns/tabs?
Comment on attachment 273843 [details] [diff] [review]

r=bzbarsky.  I assume that at this point there will never be unescaped nulls in that string, right?
Attachment #273843 - Flags: review?(bzbarsky) → review+
correct, nsSimpleURI::SetSpec escapes them (NS_EscapeURI does that even with OnlyNonASCII flag)
I think escaped whitespace should just be passed through, personally... just like escaped spaces, escaped quotes, etc.
XP Pro SP2 - IE 7 and full updates/patches with Firefox installed is vulnerable 

XP Pro SP2 - IE 6 and Firefox - not vulnerable 

Tested with a clean new VM.
Comment on attachment 273843 [details] [diff] [review]


Seems a shame to hurt any handler legitimately using %00 just because IE7 damaged a subset of common protocols.

On the other hand %00 has caused trouble in the past, maybe on the trunk we should kill it in a more common layer.
Attachment #273843 - Flags: superreview?(dveditz) → superreview+
hrm... I don't really want to kill it in more places than necessary, because it can be used for legitimate reasons too
Attachment #273843 - Flags: approval1.8.1.6?
Attachment #273843 - Flags: approval1.8.0.13?
Comment on attachment 273843 [details] [diff] [review]

approved for, and

Remember that is off GECKO181_20070712_RELBRANCH and needs a separate checkin from the on the main 1.8 branch
Attachment #273843 - Flags: approval1.8.1.7+
Attachment #273843 - Flags: approval1.8.1.6?
Attachment #273843 - Flags: approval1.8.1.6+
Attachment #273843 - Flags: approval1.8.0.13?
Attachment #273843 - Flags: approval1.8.0.13+
Checking in nsExternalHelperAppService.cpp;
/cvsroot/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp,v  <--  nsExternalHelperAppService.cpp
new revision: 1.323; previous revision: 1.322

Checking in nsExternalHelperAppService.cpp;
/cvsroot/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp,v  <--  nsExternalHelperAppService.cpp
new revision:; previous revision:

Checking in nsExternalHelperAppService.cpp;
/cvsroot/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp,v  <--  nsExternalHelperAppService.cpp
new revision:; previous revision:

Checking in nsExternalHelperAppService.cpp;
/cvsroot/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp,v  <--  nsExternalHelperAppService.cpp
new revision:; previous revision:
Closed: 14 years ago
Resolution: --- → FIXED
I backed this out of trunk for the moment, the tree was red
Resolution: FIXED → ---
Please help us with tests cases to verify this bug. Not being able to reproduce the problem explained in the blog may serve as verification, but if there's anything else we could test that you can think of, please make suggestions.
Checking in nsExternalHelperAppService.cpp;
/cvsroot/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp,v  <--  nsExternalHelperAppService.cpp
new revision: 1.326; previous revision: 1.325
Closed: 14 years ago14 years ago
Resolution: --- → FIXED
As for testcases, make sure that URLs containing null bytes don't work, e.g.:

<a href="">Link</a>
<a href=";bar">Link</a>

Perhaps also a JavaScript-created link with \x00 in the href.

Attached file TESTCASE: Based on code in comment #14 (obsolete) —
I have tested the 2 mailto links to not launch the mail client.
The j/s link does however.  Not sure if I coded this right as I am not adept at j/s.
Attachment #273999 - Attachment is obsolete: true
Secunia has done some more research on this issue. They claim, that not "%00" but "%" itself triggers the problem. In fact the modified link

<a href="mailto:%../../../../../../windows/system32/cmd".exe ../../../../../../../../windows/system32/calc.exe " - " blah.bat>Mailto:%</a>

starts calc.exe on my Windows XP system. So please check, that your patch includes this.

bye, ju
Attached file Testcase for Secunia mailto:% (obsolete) —
Secunia detected, that "mailto:%" is enough to trigger the bug.
It appears that IE7 changes *both* the behavior of windows and its own encoding of the URLs.  We could use some help trying to understand the behavior of Windows and IE with the different scenarios here.  In particular in bug 389106 there is a nice list of protocol handlers for windows and an exe that you can register to get the URL output.  The tests to run:

For each protocol register in that list register the .exe as the handler and try URLs's with % and %00 in each of the following scenarios:

System: XPsp2IE6:

Run from Start Menu -> resulting URL passed to handler
Run from IE6 -> resulting URL passed to handler
Run for FF2006 -> resulting URL passed to handler

System XPsp2IE7

Run from Start Menu -> resulting URL passed to handler
Run from IE7 -> resulting URL passed to handler
Run for FF2006 -> resulting URL passed to handler

Attached file % triggers the bug (obsolete) —
added Secunias original demo without detour over cmd.exe.
Attachment #274154 - Attachment is obsolete: true
This will add the windows protocol handlers under HKEY_CURRENT_USER pointing to the testurl.exe which is also contained within this installer. After you have finished it will attempt to restore any protocol handlers it replaced and it will just delete protocol handler it has added. I say attempt because I found that it wasn't reliable but I found that displaying a messagebox in the macro appears to have fixed this. If it doesn't work the original regkey has been saved to the installation directory's backup directory and can manually delete the key under HKEY_CURRENT_USER\Software\Classes\ and add it back by double clicking the protocol's file (e.g. protocolname.reg).

The default install location is in your documents folder and to uninstall you will have to run uninstall.exe from within this folder (the default name is protocoltest).
Also, if testurl.exe doesn't launch you may have the associated app for a protocol running. By using the HKEY_CURRENT_USER registry keys - which is safer in regards to restoring the settings - I am unable to overwrite the ddeexec keys so the app uses them they will pick up the url if it is already running. All you should have to do to remedy this is exit that app. I also didn't add keys for the shell protocol so don't bother testing it. So far my tests show that the keys are restored successfully with the additional messagebox.
sorry - had the encoding wrong in the last testcase.
Attachment #274230 - Attachment is obsolete: true
One last note... hopefully... if the app does support dde the OS will display an error even though testurl.exe launched successfully. The error can be ignored and the test output is just as valid.
Attached file NSIS script
Besides NSIS this requires the testurl.exe to be in the same dir as the script when compiling and the registry plugin from
(In reply to comment #17)
> They claim, that not "%00" but "%" itself triggers the problem.

It's not mere presence of '%', a valid percent-encoded value (other than %00) does NOT trigger the problem (e.g. %20, %FF). % followed by two characters that are not valid hex digits, or %00 trigger the problem.

> So please check, that your patch includes this.

Our patch does not. But IE7 will pass an unencoded '%' to most protocols (except the "web" ones) so we can't strip it willy-nilly and still be compatible. We're in kind of a bind here. Systems with IE6 installed are different, too, as is Vista.

Leaving apart the system-specific aspects we could do something like

 webprotocols = /^https?:|^ftp:|^mailto:|^s?news:|^nntp:|^telnet:|^gopher:/;
 badencoding = /(^[^?#]*)%(.?[^0-9a-fA-F]|00|$)/;
 if (webprotocols.test(uri) && uri.match(badencoding)) {
    throw "bad encoding in schemes treated special by Windows";

Except we'd have to do that in C++ in the windows-specific LoadURIInternal()
... and first verify that the list of "web" protocols is complete and that our conclusion that only %00 and %-invalid trigger the problem is correct.
Here's a testpage built from the protocol list in attachment 273656 [details] (bug 389106)
Using an unreadable/unmaintainable regexp is asking for trouble. Maybe we should just give up and bypass ShellExecute() entirely, pulling the command-line out of the registry and call it ourselves.

But then we have to reverse-engineer what replacement parameters ShellExecute() will handle. In the list Rob put together in bug 389106 I can see "%L" and "%l" (upper- and lower-case L) mixed in with the usual "%1" (digit 1), as well as a couple with %1 %2 (?). Is it just the first %x?

The docs for registering a protocol handler on windows say to use "%1"
Based on the email discussions going on, it looks pretty obvious we need to rework this handling completely. I'll try and get things kicked off here - 

In general, with IE6 installed we appears immune to the mailto example, however this isn't really important. As someone pointed out via email, we don't handle these web protocol handlers correctly. We generally trust SE to keep us safe, and that doesn't appear to have been the right approach.

The current proposal is to do something along these lines with some comments added -

1. Detect that an external protocol handler is invoked (mailto:blah)

2. Parse out the protocol definition, i.e. everything to the left of the first colon (mailto)

3. Look up the protocol definition in the registry under HKCR 

4. If there is no value under the protocol definition called “URL Protocol” this is not a valid protocol. Error out.

5. If it is a valid protocol open HKCR\<protocol>\shell\open\command and read the default value 

This is where things get a little sticky, there are multiple formats here we would need to deal with, and we may want to expand environment strings at this point as well.

 - read the full command template from shell/open/command
 - detect "known" executable types we want to support (an application, a rundll32.exe handler, others) 

There are other ways in which these handlers can be configured besides an app or rundll, a good example might be rlogin on vista -

url.dll,TelnetProtocolHandler %l

(To mitigate this quickly we might adopt a short list of supported handler templates, and expand on that as bugs related to the more exotic handlers show up.)
 - separate the handler from the parameter template
 - replace the appropriate parameter token with our url  (%1, %l %L - we need to track down the docs on what the differences are here, honestly ive not run into '%L' until today.) 

Also should we be applying any security related sanity checks on the URL were about to hand off?

6. Use shellexecute to launch the handler, with the appropriate parameter string.

Just a start, more research is needed to make sure we do not open up a new hole by handling these inappropriately.
Also, some test results - last night I spent mostly with IE6, and was unable to get calc to launch. After an upgrade to IE7, I've confirmed the calc / mailto thing works. The parameter looks like this:

There are 1 arguments in the URL
Argument 0:     mailto:test%../../../../testurl.exe.cmd
Some additional notes - 

- %l or %L vs. %1 implies the use of a long file name
- a dll handler without rundll in the template implies the use of rundll32.exe.
I haven't found any way to exploit this without having an unencoded double quote in the URL; so perhaps the changes in bug 389106 would also protect us from this?
Although I haven't run across any that actually use these yet, %d and %0 also replaced with the URL for registered handlers. Other %-digits are replaced with nothing, most other %-letter are replaced with the letter except:

%h is replaced with 0
%i is :#:PID  where PID is the process ID of the calling program
              (IE or Firefox) and the number (#) changes every call
              but I'm not sure what it is. Handle? Clock slice?
%s is replaced with 1

Multiple replacements happen, too, so at least we don't have to look for one or the other. "%1" "%L" "d" results in 3 copies of the URL passed to the handler.
And then we'd have to duplicate the DDE calling path, too.

#4 in comment 30 is bug regardless of whether we use ShellExecute as we are now or do the more indepth duplication of Windows behavior. bug 389611, fixed on trunk, ready to land on branch if we want to re-spin for it.
We received a response from Microsoft that in addition to the schemes listed in comment 0 they also treat "wais", "file", and "mk" in this manner when IE7 is installed. The normalization is done by the CreateUri function in accord with RFC 3986 as described at

This is purely an experimental patch that avoids major changes by vetting URI through the newer CreateUri available post IE7.
I ran Rob's NSIS installer script to register some protocols listed on, as well as the
testurl.exe command-line shell, to verify that the first URI in the bugzilla
attachment triggers the testurl.exe to run, but not the 2nd and 3rd ones, which
usually have "%00" or "%[invalid char]".  Verifying this as fixed, then, using
a Thunderbird version (20070809) (release candidate) build.

Replacing fixed1.8.0.13 with verified1.8.0.13.
Created bug 394974 to track the remaining work (namely, addressing comment 17 on including the work done in comment 37)
Alias: CVE-2007-4041
I've actually done the verification legwork for both this and bug 394974 over in that bug (I did more than I mentioned there, actually; I ran the first of the set of three as well, but only reported on the others).

See for more details.

Additionally, I ran Juergen Schmidt's testcases in this bug using Windows XP SP2 with IE 6 installed, Windows XP SP2 with IE 7, and Vista.

Replacing fixed1.8.1.8 keyword with verified1.8.1.8 keyword, since I used Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20071008 Firefox/ on the three OS flavors to test.
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.