A simple VBScript may be enough to allow users to gain administrative privileges and bypass UAC entirely on Windows 10. In a new report from a PwC UK security researcher Wietze Beukema, we learn that almost 300 Windows 10 executables are vulnerable to DLL hijacking. “It turns out nearly 300 executables in your System32 folder are vulnerable to relative path DLL Hijacking. Did you know that with a simple VBScript some of these EXEs can be used to elevate such executions, bypassing UAC entirely?” explained Beukema. The vulnerability referred to here is relative path DLL hijacking, which is when an attacker can cause a legitimate Windows executable to load an arbitrary DLL of the attacker’s choice, most likely with malicious intent. DLL hijacking attacks can prove useful to a skilled attacker as they grant capabilities such as arbitrary code execution, privilege escalation, and persistence on the target system. The various techniques of DLL hijacking covered by the Beukema’s blog post include DLL replacement, DLL Proxying, DLL search order hijacking, Phantom DLL hijacking, DLL redirection, WinSxS DLL replacement, and relative path DLL Hijacking.

A working example

To demonstrate relative path DLL hijacking in practice, Beukema focused on the libraries present in the “C:\Windows\System32” folder on a Windows 10 (v1909) machine. He copied the legitimate winstat.exe process into the downloads folder on his system. He then ran process monitoring tool, procmon, to get a better understanding of what DLLs the EXE is looking for during execution.
Process monitor showing accessed DLLs
Process monitor showing accessed DLLs Source: wietzebeukema.nl
“This allows us to identify all DLLs queried by each application, which will be all potential hijackable DLL candidates. But it does not automatically follow that all of these are also loaded (and therefore executed),” explained the researcher. “The most reliable way to find out which DLLs are properly loaded, is to compile our own version of the DLL, and make it write to a unique file upon successfully loading. If we then repeat the above approach for all target executables and DLLs, it will result in a collection of files that tells us which DLLs are confirmed vulnerable to DLL hijacking.” What poses a challenge for the attacker, though, is compiling a custom version of DLL that can be launched by the executable, without any issues. To get a reliable understanding of a legitimate DLL structure, Beukema recommends using tools like DLL Export Viewer for analysis.

This tool provides insight into the DLL structure we are trying to recompile by enumerating all external functions names that would then be duplicated in a DLL Hijacking exploit.

Approach to finding vulnerable executables
Approach to finding vulnerable executables Source: wietzebeukema.nl
The researcher has provided a comprehensive list of libraries that are good candidates for hijacking attacks. He added, “these are not mere theoretical targets, these are tested and confirmed to be working. The list comprises 287 executables and 263 unique DLLs.” A CSV with a complete list of these libraries has been provided via GitHub.

Some limitations

Some caveats, as explained by the researcher for this example attack include:
  • Only running executables that do not require any arguments
  • Avoiding applications that come with advanced GUI and error-reporting capabilities
  • Avoid DLLs written in C++.
The researcher had tested this on Windows 10 64bit  (OS build 18362.476) but says, “Some of [the DLLs] will not work [on 32-bit Windows.] You can compile C file with 32bit GCC then will work well.” Note, the attack explained here may not work with all Windows builds, as highlighted in a Twitter thread.

Bypassing UAC

Windows User Account Control (UAC) is a security feature added in Windows Vista and above, which asks the user if they intended to run a high-risk application before it is executed.
UAC Prompt
Windows UAC prompt Source: BleepingComputer
As users are repeatedly asked to authorize legitimate processes, which can get annoying fast,  starting with Windows 7, Microsoft introduced inbuilt “exceptions” within the UAC framework. Effectively, this allows trusted system DLLs to “auto elevate” privileges without having to bother users with UAC prompts. “With this in mind, you could try running arbitrary code with elevated privileges by using an executable that is marked for auto elevation that is also vulnerable to DLL hijacking. There are about 35 of such executables, as can be seen in the previous section,” explained Beukema. If successfully exploited, executed malicious DLLs could be used to created elevated command prompts that give full access to the computer with administrative privileges.
DLL Hijacking launching an elevated command prompt
DLL Hijacking launching an elevated command prompt Source: Wietze Beukema
There comes a roadblock here, though. Before “auto elevating” privileges of any DLL, the OS expects those DLLs to be present in a trusted directory, which is not user-writable. “The problem to overcome is that of the trusted directory: both the auto-elevate executable and the custom DLL need to be located in a trusted directory, but none of these are user writeable.”

Some imitation techniques come in handy here, such as creating a mock “C:\windows \system32” directory (with a trailing space right after windows). This unusually named folder may trick an executable into treating the attacker-created directory as a “trusted location.”

There is some debate if being able to create such directories should be treated as a security vulnerability as it provides a pathway for an attacker to exploit DLL hijacking vulnerabilities. “It is debatable whether this is a proper security vulnerability – Microsoft argue it is not, but it is at least a flaw, given that most (non-enterprise) Windows computers are using ‘administrator accounts’ by default. Either way, this provides us with an excellent means through which DLL hijacking can be made much more powerful,” said the researcher.

But why, VBScript?

One of the reasons the author suggests using VBScript is because creating Windows directories whose names contain a trailing space is not something that can be achieved via “traditional means.” “You could compile some lines of C to do this, as is done by the original researcher, but it turns out VBScript can actually do this for us too. The following proof-of-concept shows that with only a few lines of code you can get this to work:”
A PoC written in VBScript that creates mock “trusted directories”
A PoC written in VBScript that creates mock “trusted directories” Source: Wietze Beukema
When questioned by a user, Beukema explained why he picked VBScript when exploiting executables vulnerable to DLL hijacking. “I know… it’s just because PowerShell won’t let you do it, whereas VBScript will. And because it’s VBScript, you won’t need to bring your own compiled binaries to use this trick, meaning that apart from your custom DLL you can do everything with Living of the Land + scripts”

Detection and prevention techniques

Beukema presents a few prevention methods that can be used to deter such attacks, such as looking for activity in the mock windows \ folder, should one be present on your machine. Also, adjusting UAC settings to “always notify” could help prevent attacks like this, should the end-user be savvy enough to understand what is about to be executed. Another strategy is monitoring instances of DLL creation and loading from unexpected file paths: “You could hunt for the creation or loading of any of the DLLs mentioned before from unexpected paths, particularly in temp locations such as %appdata%. After all, the name of the (legitimate) application loading the DLLs can be changed, but the filenames of DLLs are always fixed.” When building applications, Beukema suggests, developers should enforce using absolute and not relative paths for loading DLLs, among several other techniques. None of these may alone be sufficiently foolproof. However, when appropriately applied in conjunction, preventative measures such as those explained by the researcher can deter DLL hijacking attacks by a long shot.