almost all executable installers (and self-extractors as well
as "portable" applications too) for Windows have a well-known
(trivial, trivial to detect and trivial to exploit) vulnerability:
they load system DLLs from their "application directory" (or a
temporary directory they extract their payload to) instead of
| To ensure secure loading of libraries
| * Use proper DLL search order.
| * Always specify the fully qualified path when the library location
| is constant.
| * Load as data file when required.
| * Make use of code signing infrastructure or AppLocker.
This vulnerability is typically attacked via "carpet bombing"
alias "directory poisoning", for example conducted per "drive-by"
downloads: see <http://seclists.org/fulldisclosure/2012/Aug/134>
Unsuspecting users who run vulnerable executable installers or
self-extractors (and of course "portable" applications too) from
their "Downloads" directory are the typical victims.
To make things worse: executable installers (and all DLLs they load)
are typically run with administrative privileges, either due to
their application manifest (specifying "requireAdministrator") or
the "installer detection" of Windows' "user account control" (see
"protected" administrators are prompted for consent, unprivileged
standard users are prompted for an administrator password.
Mitigations for developers and vendors:
0. DON'T BUILD EXECUTABLE INSTALLERS AND SELF-EXTRACTORS!
Use the platform's native package format, either .MSI or .INF
(plus .CAB) instead to distribute your software/files!
1. ALWAYS use fully qualified (absolute) paths in ALL references
to executables and DLLs!
2. Call SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)
to remove the application directory from the DLL search path!
Create a load-time dependency (i.e. use a static import) for
this function: this lets your installers and self-extractors
fail on systems older than Windows 8 when the optional update
backports this function to Windows Vista, Windows 7 and Windows
Server 2008 [R2]) is missing there: better be safe than sorry!
CAVEAT: this fixes the vulnerability for runtime dependencies
only, but not for load-time dependencies!
NOTE: the load-time dependency to SetDefaultDllDirectories()
is safe: KERNEL32.DLL is one of the "Known DLLs"
3. Test your installers:
a) Create a UAC-enabled "protected" administrator test account;
b) Create an empty file "C:WindowsDebugSAFER.Log" and grant
your test account at least "append" permission; remove all
permissions for all other accounts;
c) Enable Software Restriction Policies, without restrictions,
with advanced logging, for all users and all executables:
--- LOG_ONLY.REG ---
"DefaultLevel"=dword:00040000 ; 'Unrestricted'
"PolicyScope"=dword:00000000 ; Users & Administrators
"TransparentEnabled"=dword:00000002 ; All executables and DLLs
--- EOF ---
d) Logon with your test account;
e) Create an empty directory (or use the "Downloads" directory);
NOTE: on Windows XP (Windows Embedded POSReady 2009 is in
extended support until April 2019) use the existing
"%SystemRoot%System32DLLCache" instead and skip the
f) Open a command prompt in the choosen empty directory and run
the following command line to create hardlinks to all system
DLLs (more precise: all DLLs found in the PATH) there:
For %! In ("%PATH:;=" "%") Do For %? In ("%~!*.dll" "%~!*.ax" "%~!*.acm" "%~!*.drv" "%~!*.ocx" "%~!*.tsp"
"%~!*.ime""%~!*.iec") Do MkLink /H "%~nx?" "%?"
NOTE: if "MkLink /H" fails, use "Copy" (with switched arguments)
NOTE: on x64 systems this "copies" the 64-bit DLLs.
Almost all installers are but 32-bit, so use the 32-bit
CMD.EXE to run this command line there!
g) Copy your installers into this directory and execute them per
h) Determine the DLLs your installers loaded from the "application
directory" by running the following command line in the still
open command prompt:
FIND.EXE /I "%CD%" "C:WindowsDebugSAFER.Log"
i) Fix the vulnerable installers and retest them.
Mitigations for (end) users and (their) administrators:
0. Don't run executables from the "Downloads" directory or a "%TEMP%"
1. DON'T USE EXECUTABLE INSTALLERS OR SELF-EXTRACTORS!
If your favourite applications are not distributed in the native
installer package format of the resp. target platform: ask^WURGE
their vendors/developers to provide native installation packages.
If they don't: dump these applications, stay away from such cruft!
2. Deny execution (at least) in the "Downloads" directory and all
"%TEMP%" directories and their subdirectories:
* Add the NTFS ACE "(D;OIIO;WP;;;WD)" meaning "deny execution of
files in this directory for everyone, inheritable to all files
in all subdirectories" (use CACLS.EXE /S:<SDDL> for example);
* Use "software restriction policies" resp. AppLocker.
Consider to apply either/both to every "%USERPROFILE%" as well as
"%ALLUSERSPROFILE%" alias %ProgramData%" and "%PUBLIC%": Windows
doesn't place executables in these directories and beyond.
See <http://home.arcor.de/skanthak/SAFER.html> as well as
or <https://books.google.de/books?isbn=1437914926> and finally
3. Install the optional update
(available via Windows Update) and create the registry entry
to remove the current working directory from the DLL search path.
4. On Windows Vista, Windows 7 and Windows Server 2008 [R2] install
the optional update <https://support.microsoft.com/en-us/kb/2533623>
(available via Windows Update).
5. Disable UAC's privilege elevation for standard users and installer
detection for all users:
"ConsentPromptBehaviorUser"=dword:00000000 ; Automatically deny elevation requests
6. Remove the user accounts created during Windows setup from the
"Administrators" group and place them in the "Users" group, i.e.
demote these accounts from "Administrator" to "Standard user".
Start->Run "CONTROL.EXE UserPasswords2" alias
"RUNDLL32.EXE NETPLWIZ.DLL,UsersRunDll" allows this operation!
| There are three types of accounts. Each type gives you a different
| level of control over the PC:
| * Administrator accounts provide the most control over a PC, and
| should be used sparingly. You probably created this type of
| account when you first started using your PC.
| * Standard accounts are for everyday use. If you're setting up
| accounts for other people on your PC, it's a good idea to give
| them standard accounts.
JFTR: don't forget to enable the builtin "Administrator" account.
NET.EXE User Administrator /Active:Yes