Mozilla Compatible Silverlight 4 Plugin Requires Loading DLLs from CWD

chrome-silverlight-agcore-missingI visited a site yesterday in Chrome that tried to load Silverlight to provide a video player. I have KB2264107 installed and have globally disabled loading of DLLs from the current working directory in order to mitigate luring attacks against apps that use the default insecure DLL loading behavior of LoadLibrary(). Just like the Java plugin for Mozilla, Chrome generated a big fat bonk dialog trying to load the DLLs that the Silverlight plugin uses. The specific missing file is agcore.dll, which is found in “C:\Program Files (x86)\Microsoft Silverlight\4.0.50524.0” on my system.

I tried creating a symlink to agcore,dll so that agcore.dll is in the same directory as Chrome.exe, which fixes the bonk but Silverlight doesn’t work. I just end up with a black box where the movie player should be. I also tried adding the Silverlight directory to $env:path which removed the bonk but, instead, I got the “Install Microsoft Silverlight” button. I tried various combinations of symlinking DLLs and messing with the $env:path but I didn’t arrive at a combination that can actually work.

The only solution that I found is to dial the CWDIllegalInDllSearch value for Chrome and Firefox to 2 (DLLs not allowed to load from CWD if CWD is any remote, network location) instead of 0xffffffff (it also works to change this globally). I then have to hope that Firefox and Chrome are careful about how they are using CWD. I hope they are setting CWD just for loading the installed plugins in “Prgram Files” but cannot be lured into loading some evil DLL from a spurious location when doing something like opening an HTML document on a USB stick.


PS> Get-ItemProperty chrome.exe, firefox.exe | select pspath,cwdillegalindllsearch | fl


PSPath                : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVer
                        sion\Image File Execution Options\chrome.exe
CWDIllegalInDllSearch : 2

PSPath                : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVer
                        sion\Image File Execution Options\firefox.exe
CWDIllegalInDllSearch : 2




Java Built with Unsupported Old Compilers

When I turned off DLL loading from the current working directory to defeat DLL pre-loading luring attacks, one of the things I discovered was that the Java plug-in was broken in Firefox and Chrome. This problem of Java finding its C library is not new at all. The tubes are choked with posts and bug reports about getting various things that are dependent on Java to work when msvcr71.dll can’t be found. The new CWDIllegalInDllSearch = 0xFFFFFFFF option just exacerbates an existing deployment problem.

PS> cd 'C:\Program Files (x86)\Java\jre6\bin\new_plugin'
PS> dumpbin /dependents .\npjp2.dll
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file .\npjp2.dll

File Type: DLL

  Image has the following dependencies:

    USER32.dll
    GDI32.dll
    ADVAPI32.dll
    MSVCR71.dll
    KERNEL32.dll
    ole32.dll

  Summary

        6000 .data
        3000 .rdata
        1000 .reloc
        7000 .rsrc
        4000 .text

The root of the Mozilla-compatible browser Java plugin problem is npj2.dll which is dynamically linked to msvcr71.dll. Because it is a plugin, the DLL loading is done by Windows on behalf of the executable and  (Chrome or Firefox) rather than the plugin. The new_plugin directory includes msvcr71.dll which probably helped if a browser changed its CWD to the new_plugin directory when loading npj2.dll but with searching CWD out of the picture it doesn’t.

Java simply doesn’t do a good job of loading its C runtime correctly on Windows. It’s not a new problem. I don’t understand why don’t just change a switch on the complier to /MT instead of /MD and statically link the C runtime into jpjp2.dll. That would make the whole problem go away.

There are also some other oddities here. There are 2 different C runtimes used in the 32-bit version of Java 6 for Windows. For some reason they are redistributing msvcr71.dll (C runtime from Visual Studio .NET 2003) and also msvcrt.dll which is supposed to be the name of the private C runtime used by Windows components. However, the msvcrt.dll in the Java directory is actually the C runtime from Visual Studio 6 or possibly a very old Platform SDK.

By implication Oracle/Sun is using the C/C++ optimizing compiler from Visual Studio 6 (1998) and Visual Studio .NET 2003 to build the 32-bit version of Java. Holy cow those are 5 and 3 versions back from the current compilers and between 12 and 7 years old. I’m pretty sure that Visual Studio 6 is no longer supported and unfortunately both predate the side-by-side C runtime distribution system that starts with Visual Studio 2005.

The x64 version of Java is even stranger. It links against a Microsoft  x64 C runtime library called msvcrt.dll. Again this is the name reserved for the private Windows platform C runtime but this msvcrt.dll has file version 6.10.2207.0 either from a very old version of the Windows Platform SDK that provided x64 compilation support prior to Visual Studio 2005 or from a tool chain that was available by request (and is no longer available) for Visual Studio 2003.

It seems like the Java team has made a bit of a fetish of using really old compilers for the Microsoft platforms. I can understand that there is a risk of breaking stuff when upgrading a tool chain but this has been taken a bit to the extreme by the Java build team. There is a cost to testing a huge platform like Java when building with a new tool chain. Sun was cash-constrained and, although popular, Java SE didn’t really make them any money directly.

Good News for Java 7 (Probably)

It looks like the problem is being addressed. OpenJDK 7 builds, it looks like Oracle is upgrading to the C/C++ compiler from Visual Studio 2010.

BEGIN WARNING: At this time (Spring/Summer 2010) JDK 7 is starting a transition to use the newest VS2010 Microsoft compilers. These build instructions are updated to show where we are going. We have a QA process to go through before official builds actually use VS2010. So for now, official builds are still using VS2003. No other compilers are known to build the entire JDK, including non-open portions. So for now you should be able to build with either VS2003 or VS2010. We do not guarantee that VS2008 will work, although there is sufficient makefile support to make at least basic JDK builds plausible. Visual Studio 2010 Express compilers are now able to build all the open source repositories, but this is 32 bit only. To build 64 bit Windows binaries use the the 7.1 Windows SDK.END WARNING.

The 32-bit OpenJDK Windows build requires Microsoft Visual Studio C++ 2010 (VS2010) Professional Edition or Express compiler. The compiler and other tools are expected to reside in the location defined by the variable VS100COMNTOOLS which is set by the Microsoft Visual Studio installer.

So maybe in 2011 Java will have its C runtime library sorted out by virtue of having a supported global mechanism to register the Visual Studio 2010 C runtime.

Java Browser Plugin for Mozilla Vulnerable to DLL Preloading Attack

chrome-java-bonkThe “Next Generation Java Plug-in 1.6.0_21 for Mozilla browsers” 32-bit version for Windows uses CWD to load its C runtime library (msvcr71.dll). If you have globally disabled loading libraries from the current working directory (CWD) by globally setting CWDIllegalInDllSearch to 0xfffffff, you will get a bonk like the one shown at the right. Firefox also fails to load the JVM but it doesn’t give any feedback about why it isn’t working.

Note that this is not a general problem with Java. Java desktop applications like Eclipse work and the Java ActiveX plugin for IE works. The problem is specific to the NSAPI plugin and this indicates that the Java plugin for Google Chrome and Mozilla Firefox is one of the applications that is vulnerable to a DLL preloading luring attack. Specifically, when a Java applet is loaded, the JVM will cause the browser to load msvcr71.dll from whatever is the current working directory for the browser.

The error can be fixed by dialing back your global CWDIllegalInDllSearch to 2 or create an exception for chrome and firefox. However, I would rather not open those programs to attack from a USB drive.

The first location that Windows uses to search for a DLL is the directory containing the binary executable. Placing a copy of msvcr71.dll in the same directory with Firefox and Chrome fixes the problem. The problem with that is if Java services the msvcr71.dll with a newer version, then Chrome and Firefox will cause the JRE to load the wrong C runtime causing bad things to maybe happen. Another option is to create a symbolic link (which requires Vista or later).

Incidentally, the mklink command is not a standalone utility, it is a built-in to the cmd.exe shell. If you want to use mklink via powershell, you need a function to invoke cmd.exe.

function mklink { & "$env:systemroot\system32\cmd.exe" /c mklink $args }

Running mklink requires Administrator privilege.

PS> cd C:\Users\breiter\appdata\Local\Google\Chrome\Application
PS> mklink msvcr71.dll 'C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll'
symbolic link created for msvcr71.dll <<===>> C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll
PS> cd 'C:\users\breiter\AppData\Local\Google\Chrome SxS\Application'
PS> mklink msvcr71.dll 'C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll'
symbolic link created for msvcr71.dll <<===>> C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll
PS> cd 'C:\Program Files (x86)\Mozilla Firefox'
PS> mklink msvcr71.dll 'C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll'
symbolic link created for msvcr71.dll <<===>> C:\Program Files (x86)\Java\jre6\bin\msvcr71.dll
PS>

With the symlink fix in place, the Java version test page loads correctly in Chrome with no bonks with loading libraries from CWD disabled.

chrome-java-crt-symlink

Microsoft Should Formally Deprecate CWD from LoadLibrary Search

Microsoft recently released security security advisory 2269637, “Insecure Library Loading Could Allow Remote Code Execution”. The gist is that the search behavior of LoadLibrary() includes the current working directory, which is not the same as the directory containing the binary executable. Typically the current working directory (CWD) is set at launch time by Windows shell shortcut (LNK) or implicitly by invoking a document with a file association. The CWD can be anywhere on a supported local or remote file system, including Windows network (SMB/CIFS) shares and WebDAV.

Most applications must load code from libraries (DLLs) in order to run. The CWD is not a trusted secure location like Program Files or System32 but for reasons of backwards compatibility with pre-Windows NT forms of Windows, CWD is searched when loading DLLs. This makes the default behavior of LoadLibrary() dangerous and many, many Windows applications are vulnerable to luring attacks as a result.

Sample Luring Attack Scenario

  • Click on a link to an MP3 in an email or web page
  • File association causes popular MP3 player to load
  • CWD is set to the remote location of the MP3 player
  • Attacker has placed a malicious DLL that the popular MP3 player loads in the same location as the MP3
  • MP3 player loads malicious DLL
  • Malicious DLL loads the real DLL so MP3 player won’t crash
  • Popular MP3 player is owned an executing evil code

    Unfortunate Default Behavior

    Your application doesn’t have to search CWD but it is the default for reasons of backwards compatibility. Developers can turn this behavior off but it is the default and you a) have to know that you need to turn it off and b) know how to turn it off.

Patch Optionally Introduces New Behavior

KB2264107 is a patch that allows you to set registry keys to change the circumstances under which CWD is considered. The simplest option is to create a new DWORD value of the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager key called CWDIllegalInDllSearch and set it to 0xffffffff. chrome-load-dll-cwd-errorThis globally disables the use of CWD for loading libraries.

My first thought was this would be fine. I’m running Windows 7 x64 with no legacy 16-bit apps. It should work fine and for me it did. The second computer I tried this on had a problem where Google Chrome 5 was unable to find avutil-50.dll. Chrome keeps its DLLs in a version-numbered subdirectory of the one containing Chrome.exe. This isn’t a part of the normal DLL search path and it seems like Chrome 5 is working around this by setting CWD to the directory which contains the DLLs before calling LoadLibrary(). Chrome 6 beta doesn’t do this which is why I didn’t notice the problem.

To fix this you can either dial the global CWDIllegalInDllSearch down to 2 which indicates CWD is allowed to be searched only if it is a local folder. Better, is to create a KEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\chrome.exe key with a CWDIllegalInDllSearch DWORD value of 2 (and remember to delete this when Chrome 6 goes stable).

I had a similar problem with the Apple Update program failing when it tried to install the latest version of QuickTime.

Developers Should Disable Loading DLLs from CWD

depI was really stunned to realize that Chrome was using this CWD load behavior. They probably didn’t realize the implications and it is insidious because it is the default. I think all developers and testers should install KB2264107 and globally disable loading from CWD. (Yes this is a PITA and it might break stuff on your box but you can suck it up and white list apps that are broken.) If your apps are broken by this then you need to fix them.

Microsoft should encourage this by formally deprecating loading DLLs from CWD with Windows 7 SP1. They need to roll it out like they did DEP. There needs to be Group Policy settings and a GUI for manipulating these registry keys along the lines of the DEP compatibility with radio buttons like “Turn on loading libraries from CWD” and “Turn off loading libraries from CWD except for those I select". With Windows 7 SP1, the default is to leave CWD turned on. By the time Windows 8 rolls around, the default is to disable CWD.

KB2264107 is Insufficient

The hotfix should probably actually provide some protection by globally disabling some form of CWD loading. Right now all it does is create the potential for you to make some registry changes which is definitely not OK for the average user. At a minimum they need to disable CWD over WebDAV (CWDIllegalInDllSearch=1) and probably all network shares (CWDIllegalInDllSearch=2). I’m curious why there is no setting to disable CWD on removable media like USB keys without cranking CWDIllegalInDllSearch all the way to 0xffffffff and disabling CWD globally.

Microsoft needs to provide a GUI and a Group Policy for managing the keys for disabling loading libraries from CWD. The Group Policy option is critical for Enterprise so that they can keep legacy apps running which can’t be modified. They also need to make it clear that loading from CWD is going to be deprecated very soon and will no longer be the default behavior in the next version of Windows.

Microsoft should also provide guidance that any app which depends on loading libraries from CWD is vulnerable. In particular, legacy line of business apps which cannot be made to run without loading libraries from CWD should not be allowed to run on a computer with network access because such apps will be juicy targets for spear phishing. In a lot of cases it should be possible to fix apps that load libraries from CWD by just moving the DLLs into the same directory as the EXE. If the app can’t be fixed, it needs to be sandboxed from the network.

Is Microsoft Screwing Over WinMo Devs?

It seems that Microsoft has decided that they are so far behind Apple and Google on their mobile platform that the only way they can catch up is to build a radically new system and totally break backwards compatibility with legacy Win CE Native APIs and also, it seems, .NET CF WinForms.

According to Windows Phone Team member Charlie Kindel,  the programming environment for Windows 7 "phone series" is .NET with Silverlight GUI and their XNA .NET-based game development platform.

That means all existing Windows CE GUIs will be broken. All apps that rely on C/C++ code will be broken. Holy crap. Am I reading this correctly?

For us, the cost of going from good to great is a clean break from the past. To enable the fantastic user experiences you’ve seen in the Windows Phone 7 Series demos so far we’ve had to break from the past. To deliver what developers expect in the developer platform we’ve had to change how phone apps were written. One result of this is previous Windows mobile applications will not run on Windows Phone 7 Series.

The expertise and familiarity with our tools is not lost. If you are a .NET developer today your skills and much of your code will move forward. If you are Silverlight or XNA developer today you’re gonna be really happy. New developers to the platform will find a cohesive, well designed API set with super productive tools.

I don’t understand what they could be thinking. I mean, it seems like consumers have moved on to iPhone and Android and Enterprises are the remaining big customers for Windows Mobile. How can it be a good idea to break backwards compatibility with custom apps built by your best customers?

I refer you to the great essay from Joel Spolsky, How Microsoft Lost the API War.

Raymond Chen answers my question

Nearly four years ago, I asked Raymond Chen why Microsoft has continued to use cryptic 8.3 filenames in Windows even though long filenames have been supported for many years. I wasn’t paying attention when Raymond answered me a year later. I just stumbled across this today.

Commenter Brian Reiter asks a duplicate of a question that was already submitted to the Suggestion Box: Darren asks why operating system† files still (for the most part) adhere to the old 8.3 naming convention.

It comes down to a handful of interesting reasons:

  1. Once a name is chosen, it can’t be changed for reasons of backwards compatibility with applications that may load a system DLL or invoke a system executable.
  2. By default all long file names are given a short file name. Loading a DLL by reference to a short and long file name into a program will yield two separate references of the DLL in memory.
  3. 8.3 filenames are know to work. If it ain’t broke, don’t fix it. Also, a related point here is that the system component installer technology in Windows XP and prior could only support 8.3 filenames. Pretty much any system component developed prior to Vista had to have 8.3 filenames. That includes some components developed for Vista while the new installer system was under development. (There a

My original question was why does the Framework Design Guidelines for .NET applications specify a totally different naming. The gist is that while native code and legacy components have the gotchas above, .NET assemblies are different because they have additional metadata including version number and public key token. In order to dynamically load an assembly, you either need to know its strong name or its full path and filename. There is very little chance of accidentally loading the wrong assembly unless you are the one building and signing the assemblies in question.

Follow

Get every new post delivered to your Inbox.

Join 84 other followers

%d bloggers like this: