Advertisement






Microsoft Windows 10 DLL Search Path

CVE Category Price Severity
CVE-2020-0619 CWE-427 $10,000 High
Author Risk Exploitation Type Date
Unknown High Local 2020-02-01
CVSS EPSS EPSSP
CVSS:4.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2020020002

Below is a copy:

Microsoft Windows 10 DLL Search Path
Hi @ll,

(a long[er] form of the following advisory is available at
<https://skanthak.homepage.t-online.de/snafu.html>)

With Windows 10 1607, Microsoft introduced the /DEPENDENTLOADFLAG
linker option, a security feature to restrict or limit the search
path for DLLs:

| On supported operating systems, this option has the effect of
| changing calls to LoadLibrary("dependent.dll") to the equivalent
| of LoadLibraryEx("dependent.dll", 0, load_flags). 
...
| This flag can be used to make DLL planting attacks[*] more difficult.
...
| An option of /DEPENDENTLOADFLAG:0x800 is even more restrictive,
| limiting search to the %windows%\system32 directory.

[*] DLL planting attacks referred to "Dynamic-Link Library Security"
    <https://msdn.microsoft.com/en-us/library/ff919712.aspx>

The above quote was taken from
<https://docs.microsoft.com/en-us/cpp/build/reference/dependentloadflag>
before 2020-01-22; according to it /DEPENDENTLOADFLAG applies to
RUNTIME linking via LoadLibrary() ... which it but WRONG.


Demonstration:
~~~~~~~~~~~~~~

0. on a current installation of Windows 10, start the command prompt
   of the Windows Development Kit and run the following two commands:

   Set CL=/Iwindows.h /W4 /Zl
   Set LINK=/DEPENDENTLOADFLAG:0x800 /DYNAMICBASE /NXCOMPAT /RELEASE /SUBSYSTEM:CONSOLE

1. build a minimal SNAFU.DLL from the following source file SNAFU.C

   __declspec(dllexport)
   BOOL WINAPI _DllMainCRTStartup(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
   {
       return TRUE;
   }

   with the following command:

   CL.EXE /LD SNAFU.C /link /ENTRY:_DllMainCRTStartup /EXPORT:_DllMainCRTStartup

2. build a minimal application SNAFU.EXE from the following source
   file SNAFU.C

   __declspec(noreturn)
   VOID WINAPI mainCRTStartup(VOID)
   {
      HMODULE hModule = LoadLibraryA("SNAFU.DLL");

      if (hModule == NULL)
         ExitProcess(GetLastError());

      if (!FreeLibrary(hModule))
         ExitProcess(GetLastError());

      ExitProcess(0);
   }

   with the following command:

   CL.EXE SNAFU.C /link /DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup

3. run the application SNAFU.EXE and display its exit code with
   the following commands:

   .\SNAFU.EXE
   Echo %ERRORLEVEL%

   The exit code is 0, proving that /DEPENDENTLOADFLAG:0x800
   does NOT limit the DLL search path for LoadLibrary() to
   %SystemRoot%\System32\!

4. when you change the return value of the DLL's entry point
   function _DllMainCRTStartup() to FALSE, the exit code is
   1114 alias ERROR_DLL_INIT_FAILED, again proving that
   /DEPENDENTLOADFLAG:0X800 does NOT work as documented above.


Due to its security impact (see "Dynamic-Link Library Security")
I reported this bug (plus two bugs in LINK.EXE, which fails to
set /DEPENDENTLOADFLAG in executable files; see the full story at
<https://skanthak.homepage.t-online.de/snafu.html>) to Microsoft's
Security Response Center, where MSRC Case 56011 was opened.

They replied to the bug demonstrated above with the following
statement, IGNORING the bugs reported against LINK.EXE completely:

| The team has finished their investigation and determined the way
| they will address this report is via a documentation update of
| https://docs.microsoft.com/en-us/cpp/build/reference/dependentloadflag?view=vs-2019.
|
| It wasn't supposed to say that LoadLibrary will act as LoadLibraryEx,
| specifically this statement: 
|
| On supported operating systems, this option has the effect of
| changing calls to LoadLibrary("dependent.dll") to the equivalent
| of LoadLibraryEx("dependent.dll", 0, load_flags). Calls to
| LoadLibraryEx are unaffected. This option doesn't apply
| recursively to DLLs loaded by your app.


On 2020-01-24 the documentation update went live; it now reads:

| Sets the default load flags used when the operating system resolves
| the statically linked imports of a module.
|
|  /DEPENDENTLOADFLAG[:load_flags]
|
| load_flags
| An optional integer value that specifies the load flags to apply
| when resolving statically linked import dependencies of the module.
| The default value is 0. For a list of supported flag values, see
| the LOAD_LIBRARY_SEARCH_* entries in LoadLibraryEx.
...
| [...] if you specify the link option /DEPENDENTLOADFLAG:0x800
| (the value of the flag LOAD_LIBRARY_SEARCH_SYSTEM32), then the
| module search path is limited to the %windows%\system32 directory.


The changed documentation is but STILL wrong, /DEPENDENTLOADFLAG
also FAILS to restrict the DLL search path for LOADTIME linking.

JFTR: for the definitions of RUNTIME linking and LOADTIME linking,
      see <https://msdn.microsoft.com/en-us/library/ms685090.aspx>
      and <https://msdn.microsoft.com/en-us/library/ms684184.aspx>


Demonstration (continued):
~~~~~~~~~~~~~~~~~~~~~~~~~~

5. build another minimal application SNAFU.EXE from the following
   source file SNAFU.C

   __declspec(dllimport)
   extern BOOL WINAPI _DllMainCRTStartup(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);

   __declspec(noreturn)
   VOID WINAPI mainCRTStartup(VOID)
   {
      ExitProcess(_DllMainCRTStartup != NULL);
   }

   with the following command:

   CL.EXE SNAFU.C SNAFU.LIB /link /DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup

6. run the second application SNAFU.EXE and display its exit code
   with the following commands:

   .\SNAFU.EXE
   Echo %ERRORLEVEL%

   The exit code is 0, proving that /DEPENDENTLOADFLAG:... does
   NOT limit the DLL search path for Windows' module loader!

7. When you change the return value of the DLL's entry point
   function _DllMainCRTStartup() to FALSE, Windows module loader
   shows a message box and the exit code is 0xC0000142 alias
   STATUS_DLL_INIT_FAILED, again proving that
   /DEPENDENTLOADFLAG:0x800 does NOT work as documented!

8. When you erase SNAFU.DLL and run SNAFU.EXE, Windows module
   loader shows a message box and the exit code is 0xC0000135
   alias STATUS_DLL_NOT_FOUND, which is the expected behaviour
   if /DEPENDENTLOADFLAG:0x800 would work as documented and limit
   the DLL search path to %SystemRoot%\System32\


stay tuned, and don't trust unverified or incomplete documentation
Stefan Kanthak

Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum