Creating coverage for hypothetical adversary behaviors may not seem like the best use of time when there are so many known evils for which we could improve detection, but occasionally those hypothetical detection ideas pay off.
My buddy Mike Haag (who is now at Splunk) is arguably the best threat hunter out there. When Mike was finding evil on a daily basis here at Red Canary, he’d frequently find adversaries using techniques that our existing analytics did not detect, and he’d write up a coverage gap issue to be addressed. One of the recurring issues he’d write up was related to DLL Search Order Hijacking (T1574.001). One manifestation of that technique involves moving legit system binaries into unusual directories along with malicious dynamic link libraries (DLL), effectively gaming the natural DLL search order (more on this in a moment). Adversaries would frequently switch up the binaries they were abusing, subverting detection logic built around our expectations about those binaries, and resulting in a cat-and-mouse game.
DLL and search order refresher
From a very high level, a dynamic link library (DLL) is essentially a resource that can be used by multiple binaries, reducing the need for duplicative or unnecessary code. If a binary needs to use a function within one of these DLLs, it can load the DLL into memory and inherit the ability to execute that function. In practice, DLLs usually contain an export table that includes a list of functions that are available for import by executables.
When a binary loads a DLL, it has to know where the DLL exists on disk, but it can reference the DLL in a number of ways. One of the most common ways is to reference the DLL’s name within the executing binary, causing the operating system to enumerate through a number of locations in a predefined order to locate and load any DLL by that name. As you might have guessed, this DLL search order process is ripe for abuse. More details on the exact DLL search order are available directly from Microsoft.
DLL Search Order Hijacking
With enough development knowledge, an adversary can craft a malicious DLL that shares its name and exported functions with a legitimate one, but which actually contains a custom payload. The adversary can then place this malicious DLL in an appropriate directory and cause the executing binary to load the custom DLL payload. For example, an adversary can move a legitimate system binary to an unusual directory and place a malicious DLL that shares its name with a legitimate one in that same directory. When the relocated binary goes looking for the legitimate DLL, it will find and run the malicious one that’s in the same directory first.
Typically, we don’t see adversaries overwrite existing DLLs on disk, for a number of reasons. One of the main reasons is that it may cause the endpoint to become unstable, resulting in the malicious DLL being identified, the host being re-imaged, and the adversary losing their foothold. Instead of conspicuously overwriting the legit DLL with a malicious one, adversaries write these system binaries somewhere else on disk along with a malicious DLL in the same directory as the system binary, allowing the malicious DLL to be loaded into memory when the relocated binary executes.
Depending on your level of visibility into your environment, you may only see the process executing from an obscure directory. From our perspective, DLL Search Order Hijacking seems to be gaining popularity, in part because it can be difficult to detect but also because blocking suspect binaries outright can cause serious issues on a host. Trying to actively identify all of the DLLs being written to disk is also extremely difficult at scale, and attempting to identify every binary that loads a DLL from the same directory requires a large amount of processing for very little reward.
DLL Search Order Hijacking seems to be gaining popularity, in part because it can be difficult to detect but also because blocking suspect binaries outright can cause serious issues on a host.
We’ve tried a few different approaches to detecting DLL Search Order Hijacking, but the one that’s been most successful for us involves monitoring for relocated instances of system binaries. In the example below, we’re examining a native Windows binary called the Share Creation Wizard (
shrpubw.exe), and the detection logic for alerting on process path deviations is essentially as follows:
The above pseudocode represents an analytic that’s designed to look for the execution of
shrpubw.exe from a path that we do not typically expect it to execute from. Our understanding of expected paths (i.e., the normal file path for a given executable) is based on a library that we’ve been developing over a period of many years.
This library is basically a list of processes and some of their respective metadata. Both
process_path_is_unexpected? are what we call “helper detectors,” and they rely on this library to make determinations about the true identity of a given executable. We expand the list to incorporate new processes as needed.
The following is a partial example of the metadata we store for the Share Creation Wizard: