Fixing the DLL loading vulnerability

Update 24/08/2010: Microsoft published an advisory, there's an article from the MSRC about the preloading DLL vulnerability, and a tool that fixes the problem. And if you want to know more, there's an MSDN article.

Update 25/08/2010: if you came here from golem.de, heise.de or h-online.com, good for you! The articles on these websites are blatantly wrong, and their proposed solution doesn't work . You will find here the real solutions, and links to the relevant blog posts and advisories.

Look! A new shiny vulnerability, affecting a lot of Windows applications! OMG OMG OMG we're DOOMED!

</crazy mode off>

OK, let's get serious. This vulnerability is actually a very old one. It is there because the DLL search order includes the current directory (if someone can tell me why, I would be delighted to know that). Here is the search order (source: MSDN):

If SafeDllSearchMode is enabled, the search order is as follows:

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

If SafeDllSearchMode is disabled, the search order is as follows:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

For the record: disabling SafeDllSearchMode means that you're stupid, or that you're using a Windows before XP SP1 (note that this is not exclusive).

So, let's assume that your application tries to load a DLL that isn't present, either in your application directory, or in the system directories. Then, the application will try to load the DLL from the current directory. And that's it. If there's a DLL with the same name in that folder, it will be loaded in the application. That's why you can get owned by opening a file in that same directory: it sets the current directory of the application to the file's folder.

OMG OMG OMG we're DOOMED, and it's incredibly easy to exploit me!

So, now, let's take a look at the fix. This is an OS flaw. You can't fix all your applications yourself. H.D. Moore has some sysadmin fixes that you can apply to prevent the exploit from coming on your computer. But your applications will still be exploitable.

If you're a developer, though, you can fix your application. There's a function that can remove the current directory from the DLL search path: SetDllDirectory. From MSDN:

After calling SetDllDirectory, the DLL search path is:

  1. The directory from which the application loaded.
  2. The directory specified by the lpPathName parameter.
  3. The system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

So, if you pass a safe directory(let's say, C:\Windows\System32, or your application directory) as argument to SetDllDirectory, you effectively remove the current directory from the search path! It works, I tested it for you :)

But that's not the end: you have to wipe out the PATH to be safe. From the metasploit blog:

If the application is trying to load a DLL that is normally found within the PATH, but not the Windows system directories, and the PATH contains environment variables that have not been set, then the literal value of the environment variable will be treated as sub-directory of the working directory (the share). For example, if %unknownvariable%\bin is in the system PATH, the share will be searched for a directory called “%unknownvariable%\bin” and the target DLL will be loaded from within this sub-directory.

And if you test  your application with ProcMon, you will surely see that a lot of (potentially unsafe) directories are added to the PATH, and used to look for the DLL. So, remove all the useless directories from the PATH if you can!

(And now, for the disclaimer: this blog post is not endorsed by Microsoft, and if you want to be really safe and know the best solution to employ, wait for Microsoft's patches and workarounds. But if you trust me enough (you fool... *evil laugh*), you can try that fix on your application, and maybe protect your users. )

Actually, that fix is encouraged by Microsoft, and David Leblanc wrote about it in February 2008.