I’m old enough to remember the “heyday” of airline hijacking in the 1970s; not fun times, to be sure. Hopefully none of our readers have ever been impacted by a situation like that, but I’d hazard a guess that many of you have been impacted by a different type of hijacking—the Dynamic Link Library (DLL) variety. Dating back to at least 2010, DLL hijacking is nothing new and has many forms and name variations. What we’re going to touch on is known as DLL Search Order, or Load Order, Hijacking, which, if you’re a fan of MITRE ATT&CK™, is Technique T1038.
There are a lot of posts out there about DLL Hijacking, but not many (if any) cover it from an endpoint detection and response (EDR) perspective. As our faithful readers know, we leverage EDR telemetry heavily, and we know that many of you do as well. So if you have an EDR platform, what does DLL hijacking look like? This doesn’t have to be a
Dread Pirate Roberts APT type of scenario—it has historically been associated with commodity malware like Dridex, and more recently we have seen it with Emotet; we’ll demonstrate with a few “real life” detections and discuss key points along the way. In the end, you’ll have a better idea of what to look for in your environment when investigating malicious activity.
Here’s the basic setup for context: Microsoft Windows has a specific process by which an application will attempt to load a DLL into memory, unless explicitly programmed into the application. More info on that is available directly from Microsoft. For Search/Load Order Hijacking, the common scenario is to place a legitimate executable (EXE) in a path you (the adversary) control (or at least have full write access over), along with a malicious DLL named to match a legitimate one that will be loaded by said binary. It’s not quite as simple as just dropping an EXE and DLL and pressing “play”—it does require some knowledge and planning. For one thing, if the DLL is too common, it could already be loaded into memory by another application; in which case, your EXE will just use the code there and you’re an unhappy adversary. So without further ado …
Here we have the creation of a suspicious scheduled task, designed to execute a binary named
BdeUISrv.exe. This is our trigger, and an indicator that something isn’t right.
The tricky thing here is that we must be familiar with Windows processes to recognize that
BdeUISrv.exe is potentially a legitimate binary, which does not normally reside under the user profile, and then go digging for more info. When we do that, we start to find evidence of DLL hijacking.
Here is where
BdeUISrv.exe is written to disk under the user profile.
And right along with it, the setup for hijacking.
Note the path—they’re both in the same subdirectory; that’s a key thing, as the EXE will look in its current directory for a DLL by name before going elsewhere. Thus, the adversary doesn’t have to control multiple variables but simply drop their malicious DLL in the same directory. Obviously, it has to be a DLL name that the EXE will look for and load by default, but a little profiling ahead of time takes care of that (and you can be certain that, and more, occurs before the malware is ever deployed). As a matter of fact, a little judicious searching will identify public GitHub repositories with tools for this purpose; if it’s that easy for us, it’s that easy for malware authors.
The attack plays out from there quite simply: the scheduled task launches the legitimate
BdeUISrv.exe from its location under the user profile, which in turn loads the malicious code contained in
wtsapi32.dll into memory; effectively launching the actual payload. In addition, with the scheduled task set to run every 60 minutes, there’s persistence and continued propagation of the malware.
We also observed the malicious
wtsapi32.dll being loaded into memory by a copied instance of
rdpclip.exe in a different path under the user profile. This activity occurred a few months ago (as of the publishing of this post), and the malicious DLL is still not identified by usual reputation-based services, which seems to be rather common where DLLs are concerned.
This binary kicked off the rest of the activity, which included multiple DLL hijacking scenarios such as the following.
That was immediately followed by the creation of a scheduled task to launch
wfs.exe every 60 minutes.
And, one hour later…
Identifying DLL Hijacks
These examples show at a high level how the hijack occurs, but identifying it isn’t quite as straight-forward as it might appear here. We didn’t get the initial event data (what you might think of as an “alert”) based on the potential for DLL hijacking, which would be a rather complex thing to have for an initial trigger. Instead, the activity was raised based on other behaviors, such as:
- Creation of a scheduled task in a suspicious path (under the user, in this case)
- Script processes (such as
wscript.exe) spawning an unsigned binary (the fake DiffUtil EXE)
- Service Host process (
svchost.exe) spawned by an unexpected parent (wasn’t shown in our examples, but did raise events for analysis)
- Exporting registry hives (one of our detections also involved credential theft as part of the overall scheme)
- Et cetera
Once we had events to analyze, we were able to identify that known, legitimate Windows binaries were being written to, and executed from, unexpected paths. This was accomplished by checking the signature status, metadata, and hash values; all information provided via the EDR platform. The first concern (especially given the paths, and some of the seemingly unusual names these binaries have) is to ensure we don’t inadvertently mark them as static IOCs. But then the question becomes, “why is this binary here?” Having an understanding of DLL hijacking based on load/search order, we are able to pivot within the EDR to identify DLLs written to the same path. Lather, rinse, repeat with regard to validating whether any such files are legitimate; when they’re not, the intent becomes more obvious. A check from there to see whether they’re loaded into memory by the EXE, and we have our winner!
Here are a few steps to take if you see a binary being written to the user profile (or other unusual location) under suspicious circumstances, or the creation (or execution) of a scheduled task for the same:
- Check to see whether that binary is a legitimate Windows binary
- Identify if any DLL files are written to the same path
- Check those DLLs to see if they are legitimate, or have the same name as a legitimate Windows DLL
- If the binary was executed from the unexpected path, see whether it loaded DLLs from the same path into memory
Prevention, Mitigation, and Detection
Prevention is straight-forward. All application developers must specify a fully qualified path for all DLLs to be loaded by every single one of their executables. It doesn’t take much beyond common sense to realize that isn’t very realistic. For one thing, it would require a complete reworking of pretty much all existing operating systems and applications (built-in and third-party). The magnitude of such an undertaking makes it virtually insurmountable. Doesn’t help us in the trenches, anyway. Moving on…
Mitigation can be accomplished to a degree, especially with good security hygiene and an active patching program. In addition, Microsoft provides
SafeDllSearchMode which can be enabled (more information available from the MS link in our intro) to limit dynamic path loading. They also have the
CWDIllegalInDllSearch registry setting, which allows administrators to remove the current working directory (“CWD”), WebDAV, and UNC paths as options. As with any other security controls, test out these changes with your specific environment to make sure they won’t break anything before going into production.
Detecting this type of activity behaviorally is complicated at best; there are a plethora of binaries to be leveraged, so you’d pretty much have to have a target in mind, then define the specific hash values (a binary will execute the same, even if its name is changed), directories, or maybe signature status (but that can become more challenging depending on whether its signature is embedded with Authenticode or signed via a catalog file). You could monitor for DLLs being written to certain paths/directories, but be prepared for a lot of noise. Overall, is it impossible? No. Complicated and potentially prone to noise? Yes. There are some tools out there that may have the ability to identify the occurrence of potential DLL hijacking; however, I’ve not used any of them and cannot attest to their performance or efficacy in any way (your mileage may vary, and all that).
The good news is that having a layered or multi-faceted approach to raising activity for analysis will generally provide a solid starting point. Combined with an understanding of how DLL hijacking works and what it looks like in practice, a little bit of elbow grease, and you should have a solid methodology for identifying it when it does occur. Ultimately, this type of activity doesn’t change your opportunity to identify malicious behavior; its impact is more about bypassing controls to gain execution from within a signed binary, persistence, and propagation. It adds a layer of complexity to the malware, but it’s far from some 1337 hax0r APT secret sauce.