Secure loading of libraries to prevent DLL

advertisement
Secure loading of libraries to prevent DLL preloading attacks
Guidance for software developers
©2010 Microsoft Corporation
switech@microsoft.com
The information contained herein is provided "as is" without warranty of any kind. Microsoft disclaims all warranties, either express or implied,
including the warranties of merchantability and fitness for a particular purpose.
Executive summary
When an application dynamically loads a dynamic link library (DLL) without specifying a fully qualified
path name, Windows tries to locate the DLL by searching a well-defined set of directories. If an attacker
gains control of one of the directories, they can force the application to load a malicious copy of the DLL
instead of the DLL that it was expecting. These attacks are referred to as “DLL preloading attacks” and
are common to all operating systems which support dynamically loading shared DLL libraries.
The impact of such attacks could be that an attacker has the ability to execute code in the context of the
user running the application. When the application is being run as Administrator, this might lead to a
local elevation of privilege.
Microsoft has been made aware of renewed interest in these attacks. In order to limit the impact this
issue has on our mutual customers, Microsoft is releasing this document to the developer community to
ensure that they are aware of this issue and have the necessary tools to address the issue in their
applications.
Description of DLL preloading attacks
LoadLibrary Based Attacks
When an application dynamically loads a DLL without specifying a fully qualified path name, Windows
tries to locate this DLL by linearly searching through a well-defined set of directories, known as DLL
Search Order. If Windows locates the DLL within the DLL Search Order it will load that DLL. However, if
Windows does not find the DLL in any of the directories in the DLL Search Order, it will return a failure to
the DLL load operation.
The DLL Search Order for the LoadLibrary and LoadLibraryEx functions which are used to dynamically
load DLLs is:
1.
2.
3.
4.
5.
6.
The directory from which the application loaded
The system directory
The 16-bit system directory
The Windows directory
The current working directory (CWD)
The directories that are listed in the PATH environment variable
Now imagine the following set of events:



An application loads a DLL without specifying a fully qualified path that it expects to find in the
CWD of the application
The application is fully prepared to handle the case when it doesn’t find the DLL
The attacker knows this information about the application and controls the CWD



The attacker copies their own specially crafted version of the DLL in the CWD (assuming the
attacker has permission to do so)
Windows searches through the directories in the DLL Search Order and finds the DLL in the CWD
of the application
At this point, the specially crafted DLL will run within the application and gain the privileges of
the current user
Recommendation
To prevent this attack, applications can remove the current working directory (CWD) from the DLL
search path by calling the SetDllDirectory API with an empty string (“”). If an application depends on
loading a DLL from the current directory, please obtain the current working directory and use that to
pass in a fully qualified path to LoadLibrary.
Microsoft is also aware that some developers use LoadLibrary to validate whether a specific DLL is
present, in order to ascertain which version of Windows is being run by the user. It is important to note
that this could render the application vulnerable. If the affected library indeed does not exist on the
Windows release the application is executed on, an attacker could introduce a library with that same
name into CWD. Microsoft recommends strongly against using this technique. Instead, use the
recommended techniques described in MSDN article, Getting the System Version.
An application that loads third-party plugins and cannot force the plugins to use a qualified path for its
LoadLibrary calls should call SetDllDirectory(“”) to remove CWD and then call SetDllDirectory(“plugin
install location”) to add the plugin install directory to the DLL search path.
SearchPath Based Attacks
A similar attack exists when an application uses the SearchPath API to locate a DLL and dynamically load
the path returned by SearchPath. The default search order for the SearchPath API is:






The directory from which the application loaded
The current working directory (CWD)
The system directory
The 16-bit system directory
The Windows directory
The directories that are listed in the PATH environment variable
This is not a secure pattern and is not recommended by Microsoft.
The SearchPath function is not recommended as a method of locating a .dll file if the intended use of the
output is in a call to the LoadLibrary function. This can result in locating the wrong .dll file because the
search order of the SearchPath function differs from the search order used by the LoadLibrary function.
If you need to locate and load a .dll file, use the LoadLibrary function.
ShellExecute and CreateProcess
Variations of these issues can also exist when developers call similar functions such as ShellExecute and
CreateProcess to load external executables. Microsoft recommends that developers be careful when
loading binaries and specify the fully qualified path name. This should pose less complexity when loading
a binary as opposed to a library.
Recommended steps for software developers
Microsoft recommends that developers:

Validate their applications for instances of insecure library loads (examples of each are given
later in this paper), including:
o The use of SearchPath to identify the location of a library or component;
o The use of LoadLibrary to identify the version of the operating system.

Use fully qualified paths for all calls to LoadLibrary, CreateProcess, and ShellExecute, where
possible.

Implement calls to SetDllDirectory with an empty string (“”) to remove the current working
directory from the default DLL search order where appropriate. Note that SetDllDirectory affects
the entire process. Hence, this should be done once early in process initialization, not before
and after calls to LoadLibrary. Because SetDllDirectory affects the entire process, multiple
threads calling SetDllDirectory with different values could cause undefined behavior. In addition,
if the process is designed to load 3rd party DLLs, then testing will be needed to determine if
making a process-wide setting will cause incompatibilities. A known issue here is that when an
application depends on Visual Basic for Applications, making a process-wide setting may cause
incompatibilities.

Use SetSearchPathMode to enable safe process search mode for the process. This moves the
current working directory to the last place in the SearchPath search list for the duration of the
lifetime of the process. Using SearchPath to check for the existence of a DLL without specifying a
fully qualified path is not recommended even if safe search mode is enabled, as it can still lead
to DLL Preloading attacks.
Guidance on identifying insecure library loads
In source code, the following are examples of insecure library loads:
DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL);
HMODULE handle = LoadLibrary(result);
In the above code snippet, the application will search for “schannel.dll” using the least secure search
path. If an attacker has the ability to place schannel.dll in CWD, it will load even before the
application searches the Windows directories for the appropriate library.
HMODULE handle = LoadLibrary("schannel.dll");
In this code snippet, the application will attempt to load the library from the various application
and operating system locations described in the beginning of this document for the LoadLibrary()
call. If there is any risk that the file is not present, the application may attempt to load the file from
the current working directory. This scenario is slightly less dangerous than the one above, but still
exposes the application user to risk if the environment is not completely predictable.
The following are examples of better, more secure library loads:
HMODULE handle = LoadLibrary("c:\\windows\\system32\\schannel.dll");
In this snippet, the library is loaded directly using a fully qualified path. There is no risk of the
attacker introducing malicious code unless he already has write permissions to the application’s
target directory.
For information on the best ways to determine the system directory, please see the following resources:
1. GetSystemDirectory
2. SHGetKnownFolderPath -
SetDllDirectory ("");
HMODULE handle = LoadLibrary("schannel.dll");
In this snippet, the current working directory is removed from the search path prior to calling
LoadLibrary. This reduces the risk significantly, as the attacker would need to control either the
application directory, the windows directory, or any directories specified in the user’s path in order
to leverage a DLL preloading attack.
SetSearchPathMode (BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE |
BASE_SEARCH_PATH_PERMANENT );
HMODULE handle = LoadLibrary("schannel.dll");
On all systems that have installed security update MS09-014, this would permanently move CWD to
the very last spot in the search order. Any subsequent calls to the SetSearchPathMode function from
within that process that attempt to change the search mode will fail.
Using Process Monitor to dynamically detect insecure loads
Microsoft publishes a tool called Process Monitor, which allows developers and administrators to
closely track the behavior of a running process. Process Monitor can be used to dynamically detect
whether one of your applications may be vulnerable to this type of issue.

Download Process Monitor from the following location:
http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

Attempt to start your application with CWD set to a specific directory, for instance by
double-clicking a file with an extension whose file handler is assigned to your application.

Set up Process Monitor with the following filters:

In the event of a vulnerable path being hit, you’ll see something similar to the following:
The call to the remote file share to load a DLL indicates that this is a vulnerable program.
Additional resources
Dynamic Link Library Search Order
http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx
MSDN documentation on the SearchPath function
http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx
MSDN documentation on the LoadLibrary function
http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx
MSDN documentation on the SetDllDirectory function
http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx
MSDN documentation on the SetSearchPathMode function
http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx
Blog post by David Leblanc, Principal Security Engineer with Microsoft Office
http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx
Blog post by Andrew Roths, MSRC Engineering team on DLL preloading attacks
http://blogs.technet.com/b/srd/archive/2009/04/14/ms09-014-addressing-the-safari-carpet-bombvulnerability.aspx
Download