Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

DLL Minesweeper

Not just a game for software developers, (penetration) testers and administrators only.

Purpose

Build and use a (digital) minefield of forwarder DLLs as testbed for Windows® applications, in order to detect those vulnerable to DLL hijacking.

Reason

Although DLL spoofing alias DLL preloading, binary planting and DLL side-loading is well-known and well-documented since more than 20 years, and despite MSDN articles like Dynamic-Link Library Security and Dynamic-Link Library Search Order giving advice to avoid this beginner’s error, the vast majority of Windows programs are still vulnerable to it!
For examples see Carpet Bombing and Directory Poisoning, Downloads Folder: A Binary Planting Minefield and Bypassing Application Whitelisting.

In executable installation programs which typically need or request administrative privileges and are run from unsafe locations like the user’s Downloads directory or a %TEMP% directory where this vulnerability is trivial to exploit it becomes especially dangerous.

Operation

When loaded by a vulnerable application, each forwarder DLL ‹filename›.dll acts as transparent proxy or static redirector to its corresponding target DLL %SystemRoot%\System32\‹filename›.dll located in Windows’ system directory, accomplished by using the relative pathname System32\‹filename› of the target DLL.

Note: export forwarding is a feature of Windows’ module loader, and used in quite some Windows system DLLs.

Active use

Copy or download any program into the directory where you built the forwarder DLLs and run it.

Passive use

Copy (or hardlink) the forwarder DLLs into the system’s %TEMP% directory %SystemRoot%\Temp\ and your own %TEMP% directory %USERPROFILE%\AppData\Local\Temp\, then wait.

Limitation

export forwarding is limited to target DLLs with the .dll file extension.

Note: to include DLLs with file extension .acm, .ax, .cpl, .drv, .ime, .ocx, .tsp etc. in the testbed, for example WinSPOOL.drv, MSCTFIME.ime or HHCtrl.ocx, build forwarder DLLs for them and create hardlinks ‹filename›.dll of the target DLLs in Windows’ system directory.

Bug

ShlWAPI.dll from Windows 7 and newer versions of Windows NT exports SHCreateStreamWrapper as an invalid forward to SHUNIMPL.#UNIMPL_SHCreateStreamWrapper!

Note: ShUnimpl.dll is a graveyard for obsolete and now unimplemented functions of Windows’ shell from prior versions of Windows NT.

Prerequisites

The following prerequisites are necessary to prepare the testbed: Note: for reference and details see Prepare Your Development Environment.

Preparation

Perform the following 9 (optionally 12) simple steps to build forwarder DLLs ‹filename›.dll with exports (both by name and by ordinal) forwarded to their corresponding target DLLs %SystemRoot%\System32\‹filename›.dll located in Windows’ system directory, using import libraries and export files generated from the exports of the target DLLs.

For some of the details see the MSDN article Working with Import Libraries and Export Files.

  1. Create the text file DLLDUMMY.C with the following content in an arbitrary, preferable empty directory:

    // Copyright © 2004-2018, Stefan Kanthak <‍skanthak‍@‍nexgo‍.‍de‍>
    
    #define STRICT
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    __declspec(dllimport)
    INT	WINAPI	MessageBoxTimeoutA(HWND   hwnd,
    		                   LPCSTR lpText,
    		                   LPCSTR lpCaption,
    		                   UINT   uType,
    		                   WORD   wLanguageId,
    		                   DWORD  dwMilliseconds);
    
    BOOL	WINAPI	_DllMainCRTStartup(HINSTANCE hinstDLL,
    		                   DWORD     fdwReason,
    		                   LPVOID    lpvReserved)
    {
    	extern	const	IMAGE_DOS_HEADER	__ImageBase;
    
    	static	const	LPCSTR	szReason[4] = {"DLL_PROCESS_DETACH",
    				               "DLL_PROCESS_ATTACH",
    				               "DLL_THREAD_ATTACH",
    				               "DLL_THREAD_DETACH"};
    
    	LPCSTR			szModule = "<unknown>";
    	IMAGE_NT_HEADERS	*ntHeader = (IMAGE_NT_HEADERS *) ((LPBYTE) &__ImageBase + __ImageBase.e_lfanew);
    	DWORD			dwRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    
    	if (dwRVA != 0L)
    	{
    		dwRVA = ((IMAGE_EXPORT_DIRECTORY *) ((LPBYTE) &__ImageBase + dwRVA))->Name;
    		if (dwRVA != 0L)
    			szModule = (LPCSTR) ((LPBYTE) &__ImageBase + dwRVA);
    	}
    
    	MessageBoxTimeoutA(HWND_DESKTOP,
    	                   szReason[fdwReason],
    	                   szModule,
    	                   MB_OK | MB_ICONSTOP,
    	                   MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
    	                   12345L);
    
    	return TRUE;
    }
    For details and reference see the MSDN articles DllMain entry point and Dynamic-Link Library Entry-Point Function, plus IMAGE_NT_HEADERS structure, IMAGE_OPTIONAL_HEADER structure and IMAGE_DATA_DIRECTORY structure.

    Note: modification of the source file DLLDUMMY.C to retrieve and display more or other information than only the DLL’s (internal) name found in its export directory and the reason of the call is left as an exercise to the reader.

    Note: follow the guidance given in the MSDN article Dynamic-Link Library Best Practices when you modify the source code!

  2. Compile the object file DLLDUMMY.OBJ from the source file DLLDUMMY.C created in step 1.:

    CL.EXE /c /GA /GF /GS- /Gy /O1 /Os /Oy- /wd4100 /TcDLLDUMMY.C /Zl /nologo
    For details and reference see the MSDN article Compiler Options.
  3. Optionally link the DLL DLLDUMMY.DLL from the object file DLLDUMMY.OBJ compiled in step 2.:

    LINK.EXE /DLL /DYNAMICBASE /ENTRY:_DllMainCRTStartup /EXPORT:_DllMainCRTStartup /IGNORE:4216 /LARGEADDRESSAWARE /NODEFAULTLIB /NOLOGO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:DLLDUMMY.DLL /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.OBJ USER32.LIB
    For details and reference see the MSDN article Linker Options.

    Note: set the value of the /OSVERSION: argument to the targeted Windows version.

  4. Optionally load and test the DLL DLLDUMMY.DLL linked in step 3.:

    REGSVR32.EXE "%CD%\DLLDUMMY.DLL"
    RUNDLL32.EXE "%CD%\DLLDUMMY.DLL",*
    Note: it’s sufficient to run just one command line.
  5. Create the text file DLLDUMMY.CMD with the following content:

    @Echo Off
    
    Rem Copyright © 2004-2018, Stefan Kanthak <‍skanthak‍@‍nexgo‍.‍de‍>
    
    Echo LIBRARY %~n1
    Echo.
    Echo EXPORTS
    
    SetLocal
    For /F "Delims= Skip=16 UseBackQ" %%@ In ("%~2") Do If "%%@" == "  Summary" (Exit /B) Else Call :EXPORTS "%~n1" "%%@"
    EndLocal
    Exit /B
    
    :EXPORTS
    Set LIBRARY=System32\%~1
    Set LINE=%~2
    Set ORDINAL=%LINE:~4,7%
    Set ORDINAL=%ORDINAL: =%
    Set HINT=%LINE:~12,4%
    Set RVA=%LINE:~17,8%
    Set NAME=%LINE:~26%
    
    If "%HINT%" == "    " Goto :ORDINAL
    If "%NAME%" == "[NONAME]" Goto :ORDINAL
    If "%RVA%" == "        " Goto :FORWARD
    
    :NAME
    Echo  %NAME%=%LIBRARY%.%NAME% @%ORDINAL%
    Goto :EOF
    
    :ORDINAL
    Echo  @%ORDINAL%=%LIBRARY%.#%ORDINAL% @%ORDINAL% NONAME
    Goto :EOF
    
    :FORWARD
    Set NAME=%NAME: (forwarded to ==%
    Echo  %NAME:~0,-1% @%ORDINAL%
    Goto :EOF
    Note: modification of the batch script DLLDUMMY.CMD to target DLLs located in subdirectories of the system directory is left as an exercise to the reader.
  6. Dump the exports of an arbitrary DLL ‹filename›.dll located in Windows’ system directory %SystemRoot%\System32\ to the temporary text file DLLDUMMY.TXT:

    LINK.EXE /DUMP /EXPORTS /OUT:DLLDUMMY.TXT "%SystemRoot%\System32\‹filename›.dll"
  7. Generate the intermediary module definition file DLLDUMMY.DEF from the text file DLLDUMMY.TXT dumped in step 6., using the batch script DLLDUMMY.CMD created in step 5.:

    CALL DLLDUMMY.CMD ‹filename› DLLDUMMY.TXT >DLLDUMMY.DEF
    For details and reference see the MSDN articles Rules for Module-Definition Statements, EXPORTS and LIBRARY.
  8. Build the intermediary import library DLLDUMMY.LIB and the intermediary export file DLLDUMMY.EXP from the module definition file DLLDUMMY.DEF generated in step 7.:

    LINK.EXE /LIB /DEF:DLLDUMMY.DEF /MACHINE:X86 /NODEFAULTLIB /NOLOGO /OUT:DLLDUMMY.LIB
    For details and reference see the MSDN article Building an Import Library and Export File.

    Note: modify the value of the /MACHINE: argument when you build for a processor architecture other than I386 alias x86!

    Note: (contrary to common misinformation) forwarder DLLs built for the I386 alias x86 processor architecture of Windows NT work on the AMD64 alias x64 processor architecture as well: Windows’ module loader loads them and resolves their forwarded exports, but does not call their _DllMainCRTStartup() routine.

  9. Build the DLL ‹filename›.dll from the object file DLLDUMMY.OBJ compiled in step 2., using the import library DLLDUMMY.LIB and the export file DLLDUMMY.EXP built in step 8.:

    LINK.EXE /DLL /DYNAMICBASE /ENTRY:_DllMainCRTStartup /LARGEADDRESSAWARE /NODEFAULTLIB /NOLOGO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:"‹filename›.dll" /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.OBJ DLLDUMMY.LIB DLLDUMMY.EXP USER32.LIB
    For details and reference see the MSDN articles Using an Import Library and Export File and Linker Options.

    Note: set the value of the /OSVERSION: argument to the targeted Windows version.

  10. Erase all intermediary and temporary files:

    Erase DLLDUMMY.DEF DLLDUMMY.EXP DLLDUMMY.LIB DLLDUMMY.TXT
  11. Repeat the steps 6. to 10. for every DLL located in Windows’ system directory %SystemRoot%\System32\ to build a complete minefield.

  12. Optionally sign and timestamp all forwarder DLLs built in steps 3. and 9.:

    SIGNTOOL.EXE Sign /A /D "DLL Minesweeper" /DU "https://skanthak.homepage.t-online.de/minesweeper.html" /T "http://timestamp.verisign.com/scripts/timstamp.dll" /V *.dll
    SIGNTOOL.EXE Sign /AS /D "DLL Minesweeper" /DU "https://skanthak.homepage.t-online.de/minesweeper.html" /FD SHA256 /TD SHA256 /TR "http://timestamp.verisign.com/scripts/timstamp.dll" /V *.dll
    For details and reference see the MSDN articles Using SignTool to Sign a File and SignTool.

Download

The makefile DLLDUMMY.MAK performs the steps 1. through 11. shown above.
It contains the sources for an enhanced variant of the forwarder DLL as inline files and needs the icon DLLDUMMY.ICO.

Download both files into an arbitrary, preferably empty directory, then run the following command line:

NMAKE.EXE /R /F DLLDUMMY.MAK test sign all
Note: translations of the MESSAGETABLE and STRINGTABLE resources into other languages are welcome!

Contact

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, errors, inaccuracies, omissions, vulnerabilities or weaknesses, …:
don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Notes: I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see a full (real) name as sender, not a nickname!
Emails in weird formats and without a proper sender name are likely to be discarded.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!
Copyright © 1995–2018 • Stefan Kanthak • <‍skanthak‍@‍nexgo‍.‍de‍>