DLL Hijacking - simple technique that gives more stealth to the attack; understand - ISH Tecnologia

DLL Hijacking - simple technique, which confers greater stealth to the attack; understand

Written by: Alexandre Siviero

The recent REvil ransomware attack through the Kaseya infrastructure is the latest in a series of attacks that have incorporated a technique known as DLL Side-Loading. According to the MITRE ATT&CK framework, this is a technique for hijacking the execution flow of a process (which is why it is also called DLL hijacking). Its application is simple, even more so considering other DLL exploits such as reflected injection, and provides greater stealth to the attack. To understand it, you must first understand what DLLs are and how they are loaded by a file.

Dynamic-Link Libraries

Per Microsoft's documentation, a DLL is a module that contains functions and data that can be used by other modules. To make it even simpler, it is an executable just like a PE, but it doesn't run by itself. Its purpose is to bring modular operation to applications, for example by offering native Windows functions through APIs so that programmers don't have to reinvent the wheel. If your program will use TCP/IP communication, for example, you don't need to program all this stuff; just import the DLL that has the APIs you need (such as using sockets for network connections) and move on.

The term dynamic-link also suggests that there are other possible link types for applications: static-link and runtime-link.

Static-link

It consists of including within the code of an application absolutely all the functions necessary for it to work. No import is required during execution, but this results in compiled software with a larger size and more difficulty for updates and adjustments. Why? Because instead of fixing just one auxiliary module that your program uses, you need to mess with the source code and recompile for any change.

Dynamic-link

DLLs are imported into the memory of a process during its startup. This means that the executable on disk lists all corresponding modules and functions in an import table. During the operations that transfer an executable into memory and turn it into a process, Windows will read this table, look at the code for the functions requested in the associated DLLs and copy it into the memory of that process. It is this import table that software that analyzes executables reads.

Runtime-link

An alternative to dynamic-link, or importing DLLs and functions during process startup, is to do it during application execution (hence the term runtime). There are legitimate uses for this approach, such as not spending time or memory importing functions that will rarely be used by the process - think of it as an "on demand" import model. Malware authors are quite fond of this type of import for another reason: to obscure the functionality of their malicious software. When you know enough system DLLs, reading the import table of a disk executable gives you a lot of information about what that program will do when it runs. Nobody puts in DLLs for nothing, so if software imports something to interact with the Windows registry, it will interact with the Windows registry.

To prevent this simple kind of static analysis from showing what the malware sets out to do, the authors only import DLLs that are strictly necessary for the operation of the process via dynamic-link. All really interesting functions will be enumerated and imported during execution.

DLL Hijacking

Ok, we've talked countless times about importing, but so far without explaining how it actually works. Earlier we mentioned strictly necessary DLLs; one of them is Kernel32.dll, which provides a number of APIs used to correctly initialize a process, among them LoadLibraryA and LoadLibraryEx. Both are used to import a DLL, both in dynamic-link and runtime-link cases (the differences between the two APIs are small and irrelevant to the topic here).

Both APIs have as parameter lpLibFileName, which can provide a PE (.exe) or a DLL (.dll) to be loaded into the process. The filename passed to this parameter may or may not contain its full path (disk location). If it does, the target file will be read from the given directory and mapped into memory. But what if you provide only the file name, without its location?

In these cases, Windows will search for the file on disk following a predetermined order, which is available in Microsoft documentation. The Safe Dll Search Mode is enabled by default and affects the order of places where the executable to be imported will be searched. With it enabled, the order is:

  1. The directory from which the application was launched
  2. The system directory (C:³³Windows³System32)
  3. The 16-bit version of the system directory
  4. The Windows directory (C:³³)
  5. The current directory

With Safe Dll Search Mode disabled, the order changes to:

  1. The directory from which the application was launched
  2. The current directory
  3. The system directory (C:³³Windows³System32)
  4. The 16-bit version of the system directory
  5. The Windows directory (C:³³)

PS: I have omitted the 6th entry from the list for the sake of brevity and because it is irrelevant to the technique we are going to discuss, but the full list is available at the link to the documentation provided in the previous paragraph.

"Ahha! From the difference between the two, I bet DLL hijacking uses the current directory!". Good guess, but no. In fact, for this technique, the state of the secure search is completely irrelevant. The exploitation happens in the very first searched place, the directory from which the application was launched.

In the specific case of REvil, Sophos showed how the dropper of this attack saves an old (and legitimate) Microsoft Defender binary on disk and uses it as a target for DLL hijacking. Below, note that normally the legitimate MpSvc DLL (selected) resides in the same directory as MsMpEng.exe, one of the Defender binaries:

 

So, following the search order for imported DLLs without the full disk path, it is in the first place Windows would look. Taking advantage of this, the group simply named their malicious DLL MpSvc.dll and saved it in the same directory as the old Defender binary.

Why do it that way instead of writing malicious software and running it as a process? Because Defender running on a machine draws less attention.

Stealthy, but how much?

Any technique that deviates from normal operating system behaviour will leave traces, even stealthy ones. You can be discreet on one front, but end up being noisy on another. In the case of REvil, the old version of Windows Defender (msmpeng.exe) used as a vehicle for side-loading a malicious DLL is saved in C:\windows\msmpeng.exe. This is the first clue that something is not right: the Defender executable has always resided inside the "Program Files" directory, in the Windows Defender folder. In Windows 10, that directory has migrated to ProgramData; while different, neither path brought msmpeng.exe saved directly into the Windows directory.

Defender's parent process would also be cause for suspicion. The dropper used by the group was saved in a Kaseya folder (C:\KWORKING\AGENT.EXE) so the process tree would show Defender was started by... a Kaseya executable? It doesn't make any sense.

Of course, there are several nuances to real-time detection of such an attack. Forensic analysis would trivially show suspicious behaviour, but in ransomware cases analysing post-attack means the damage has already been done. To add more fuel to the fire, Kaseya itself recommended its customers to exclude directories of their applications from machine anti-virus. To be as clear as possible: DLL hijacking/side loading is easy to understand; it doesn't mean it is equally easy to detect and/or prevent.

Bibliography:

https://docs.microsoft.com/en-us/troubleshoot/windows-client/deployment/dynamic-link-library

https://news.sophos.com/en-us/2021/07/04/independence-day-revil-uses-supply-chain-exploit-to-attack-hundreds-of-businesses/

https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya

https://github.com/sophoslabs/IoCs/blob/master/Ransomware-REvil-Kaseya.csv

https://attack.mitre.org/techniques/T1574/002/

https://news.thewindowsclub.com/new-path-windows-defender-installation-windows-10-91061/

https://www.ghacks.net/2017/12/18/microsoft-changes-windows-defender-path-on-windows-10/