# What are DLL files? DLL (Dynamic Link Library) file is a file containing reusable code and data which multiple programmes can use at the same time to perform different functions, improving efficiency and modularity in software development. Unlike `.exe` files, `.dll` files can't be executed directly. Instead, an application will load DLL files as needed to perform specific tasks that may not be part of the core functionality of the original program. This reduces the amount of code that needs to be written, simplifies maintenance, and saves space. Unfortunately, the operation of these `.dll` files are easily abused and exploited by adversaries, which is called DLL Hijacking. # DLL search order It is important to know the order that applications search for DLL file. ![image](https://hackmd.io/_uploads/BJ5tsD4sR.png) ## Special Search Locations Special search locations are taken into account before the standard search locations, and they contain different factors that can control the locations to be searched and used to load a DLL. These locations are based on the application and the system configurations. * [DLL redirection](https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-redirection) allows specifying which DLL file should be loaded by DLL loader. * [API sets](https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets) allows dynamically routing function calls to the appropriate DLL based on the version of Windows and the availability of different features * SxS [manifest](https://learn.microsoft.com/en-us/windows/win32/sbscs/manifests) redirection redirects DLL loading by using application manifests * Loaded-module list verifies whether the DLL is already loaded into memory * Known DLLs checks whether the DLL name and path match the Windows list of known DLLs. This list resides in `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs` * The [package](https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/#advantages-and-disadvantages-of-packaging-your-app) dependency graph of the process, in case it was executed as part of a packaged app ## Standard Search Locations The standard search locations are the ones most associated with the DLL hijacking technique, and they will usually be used by adversaries. Windows will use the following order to search for the desired DLL. * The application’s directory (the directory containing the executable) * `C:\Windows\System32` * `C:\Windows\System` * `C:\Windows` * The current directory (the directory from which we execute the executable) * Directories listed in the PATH environment variable # Notable techniques of DLL Hijacking ## DLL Proxying In the context of malware, DLL proxying is a DLL hijacking technique, where a legitimate DLL say, `legit.dll` is renamed to `legit1.dll` and a malicious dll, which exports all the same functions that the legit1.dll exports, is placed instead of `legit.dll`. Once the DLL is hijacked, whenever a program calls a function, say `exportedFunction1` from `legit.dll`, here is what happens: * `legit.dll` gets loaded into the calling process and executes its malicious code, say reaches out to the C2 * `legit.dll` forwards the call to `exportedFunction1` in `legit1.dll` * `legit1.dll` executes the `exportedFunction1` This function forwarding from one DLL to another is what gives the technique its name - DLL proxying, since the malicious DLL is sitting in between the application calling the exported function and a legitimate DLL that implements that exported function. At a high-level, below diagram shows how it all looks before and after the DLL is hijacked: ![image](https://hackmd.io/_uploads/SyCaXR4nC.png) Alright, now see how this technique works: * Decide on which DLL to hijack. Let's say, it's located in `C:\Temp\legit.dll`. Move it to `C:\Temp\legit1.dll` * Get a list of all the exported functions of `C:\Temp\legit1.dll` * Create a malicious DLL malicious.dll, that once loaded by the target process, executes your payload * Inside the malicious.dll, redirect/forward all the exported functions by legit.dll (this is the DLL we are hijacking) to legit1.dll (this is still the same DLL we are hijacking, just with a new name) * Copy malicious.dll to `C:\Temp\legit.dll` * At this point, any program that calls an any exported function in legit.dll will now execute your malicious payload and then transfer the execution to the same exported function in `C:\Temp\legit1.dll`. Implementing DLL proxying for a DLL that exports many functions may be a bit painful, but luckily there are multiple projects that help you automate this process, one of which is https://github.com/Flangvik/SharpDllProxy, so go check it out. ## DLL Search Order Hijacking [DLL search order hijacking](https://attack.mitre.org/techniques/T1574/001/) offers adversaries a reliable and discrete method for persisting, elevating their privileges, and evading defensive controls. Fundamentally, the main reason that DLL search order hijacking is so popular among adversaries is that it allows adversaries to introduce malicious binaries to a host system in a way that can be exceedingly difficult to detect. Search order hijacking enables an adversary to load a malicious DLL into a process that is hosted by an otherwise legitimate, high-reputation executable. Otherwise, [this blog](https://redcanary.com/blog/threat-detection/system32-binaries/) offers insight into just how difficult it can be to gain visibility into and detect DLL search order hijacking. Some of this analysis is derived from that article. Adversaries mostly abuse this search order process by moving legitimate system binaries into non-standard directories that include malicious DLLs that are named after legitimate ones. Sticking with the example above, if `process.exe` and `module.dll` are located in the System32 directory, then `process.exe` will search through that directory, find the legitimate `module.dll`, and run it. However, an adversary can put a malicious version of `module.dll` in the temp directory and move `process.exe` to the temp directory as well. When `process.exe` executes and goes looking for `module.dll`, it’ll grab the malicious version in the temp directory rather than the original version in the system32 directory. And here's the pattern which we follow to detect: **1. Visibility** * Process Monitoring Process execution is an important optic for observing and developing detection analytics for DLL search order hijacking activity because search order abuse always occurs in tandem. That said, developing robust detection coverage for DLL search order hijacking will require defenders to incorporate other data sources as well. * File Monitoring Since DLL search order hijacking typically involves the relocation of system binaries, monitoring file activity for the execution or creation of processes from or in unexpected file paths is an important source of visibility. You’ll want to monitor for the execution of processes from unexpected file paths. * Module Monitoring Module load monitoring will offer visibility into the execution of the actual malicious DLLs. Given the volume of module loads on a given machine, this can be a voluminous data source to inspect on its own, but it can provide incredible value in combination with other telemetry. **2. Collection** * Sysmon Event ID 1: Process creation Process creation events are among the best sources of visibility into DLL search order hijacking. The telemetry logged by this Sysmon event is valuable for capturing context related to process executables that load from non-standard directories. * Sysmon Event ID 7: Image loaded Image load events are extremely valuable in supplying evidence of DLL search order hijacking as well. This log needs to be enabled, but it will record all processes that load DLLs along with corresponding hashes, signatures, and other information. * Windows Security Event ID 4688: Process Creation Process Creation (4688) events with command-line argument logging enabled is a great source of telemetry for process starts and commands lines—or, as is often the case with process injection, a lack thereof. **3. Detection** Detection for this technique is relatively easy to describe but incredibly difficult to operationalize: Alert whenever a process executes from a file path other than the one you would expect it to in your environment. This, of course, is easier said than done because it requires you to track expected file paths and compare them to file paths of processes as they execute in real time. Detection of DLL search order hijacking is based primarily on process executions that deviate from their expected file paths. The following pseudo-analytic is just one example using an arbitrary process. You can adjust the logic to apply to nearly any process that’s a common proxy for DLL search order hijacking. ```powershell process == 'shrpubw.exe' && file_path != ('windows\system32\shrpubw.exe' || 'windows\winsxs') ``` ## DLL Sideloading ### Definition DLL sideloading is a known technique often leveraged by threat actors which exploits the way Windows applications load DLLs. This technique falls under the DLL hijacking category, which consists of several methods that attackers can use to abuse these library files. DLL Search order hijacking (T1574.001) is one of the most common methods of DLL sideloading that occurs when an attacker places a malicious DLL with the same name as a legitimate DLL in a location that is searched before arriving at the legitimate DLL’s path. When the application runs, it subsequently loads the attacker’s DLL in place of the legitimate one, executing the malicious code. For example, Windows contains many DLL files in `C:\Windows\System32` which are used by many Windows and third party applications. If a third party application is vulnerable to DLL sideloading, an attacker could create their own malicious DLL named after the same in `System32`, and place it next to the vulnerable application’s executable. When the application is executed, rather than loading the DLL file in `System32`, the dropped malicious DLL (with the same name but in the executable’s folder) is executed first rather than the legitimate DLL. This technique takes advantage of the way in which libraries (DLL) are loaded from executables (EXE). By default, inside the executable, if no path is specified for the DLL, the application will first load the target DLL in its own local directory. Occasionally, programmers will specify just the name of the library versus its entire path. For example, specifying simply `dwmapi.dll` versus `C:\Windows\System32\dwmapi.dll` creates a DLL sideloading search order hijacking vulnerability. Attackers can exploit this behavior by mimicking the names of legitimate DLLs expected by genuine applications by dropping a malicious DLL named the same as one found in a legitimate directory, so the malicious DLL is loaded first. DLL side-loading is mostly used by adversaries due to advantages it brings: * DLL side-loading attacks often use legitimate, trusted, and even signed executables as their initial loader. * A number of security products and configurations have "safe lists" that specifically include many of these trusted executables. * Even if they aren’t safe-listed explicitly, there is a high likelihood that a detection involving a trusted executable will be listed as a false positive. The use of DLL sideloading in modern attack chains illustrates its effectiveness in evading detection and maintaining persistence. Practical examples in cybersecurity incidents reveal how sophisticated threat actors, including state-sponsored groups and cybercriminal syndicates, have adopted DLL sideloading to deploy various types of malware including information stealers, backdoors and even ransomware. ### Mitigation The best protection against modern cyber-attacks is a defense-in-depth architecture. After reducing your attack surface and implementing leading-edge prevention controls, lean on security operations to catch any incidents that may get through. Implement detection and response capabilities, either as a service (Bitdefender MDR) or by providing strong detection and response tools to your in-house security teams (Bitdefender XDR). For prevention, the most effective digital artifact that can lead to the detection of a DLL sideloading attack is the malicious library itself. Alert can be triggered by downloading a suspicious file (IP/domain/URL reputation capabilities are included with all Bitdefender GravityZone agents), when it is saved to a disk (on-access detection), or when it’s loaded into memory (one of the algorithms for monitoring process behavior). For **active exploitation** – a standalone binary (highly trusted) is uploaded to a target system and used to sideload a malicious library, the most important question to ask is how could threat actors gain access to write to a location where the malicious binary is searched for. The typical search order includes only locations that require elevated rights. One of the prerequisites for active exploitation is that currently installed software must be vulnerable, and threat actors need write access to the system. For **passive exploitation** - this approach is relying on the pre-installed applications or components vulnerable to loading a malicious library from an unsafe location, the system was already compromised when this detection evasion technique is used. The launching binary is not recognized as malicious, and behaves as intended, trying to locate and load a library without knowing it was compromised. Why would a threat actor put so much effort into finding these legitimate vulnerable executables when `rundll32.exe` or `regsvr32.exe` can be used to load any DLL? Both `rundll32.exe` and `regsvr32.exe` are common utilities used by threat actors, and detection and response tools like Bitdefender XDR are looking for these red flags. A valid digital signature and known publisher can further confuse some security tools. DLL sideloading allows threat actors to keep a low profile. This method can be effective only if a security solution doesn’t implement more advanced algorithms for monitoring process behavior. With modern endpoint security solutions, the malicious library should be detected and blocked. ## DLL Injection DLL injection is a method, frequently referred to as process injection, where developers and cyberattackers alter a program's functionality by executing extraneous code within another process's realm. This approach hinges on the capabilities of Windows' Dynamic Link Library (DLL), a type of file that can be loaded and executed dynamically by programs. However, it is not just limited to DLL code; we can inject code in various other forms, such as executables (EXE), handwritten code, etc. The key factor is whether we have sufficient system privileges to manipulate another application's process. In fact, Windows API provides several functions that allow us to interfere with and manipulate other programs for debugging purposes. We will leverage these APIs to perform DLL injection. I will break down the DLL injection process into four steps: * Interfere with the process * Allocate memory in the process * Copy the entire DLL or the path to the DLL into that memory and identify the location of the memory * Execute the DLL in the process Each step can be accomplished using one or more techniques, which are summarized in the images below. It is important to understand the details of these techniques, including their pros and cons, to use them effectively in different scenarios. ![image](https://hackmd.io/_uploads/Skvwi8BhC.png) To execute the DLL in the process, we have a few options such as `CreateRemoteThread()`, `NtCreateThreadEx()`, etc. We perform the memory allocation and copying steps to create the process memory space and prepare it to begin executing the DLL. Two common methods are `LoadLibraryA()` and jumping to `DLLMain`. * LoadLibraryA(): `LoadLibraryA()` is a function in `kernel32.dll` used to load a DLL, executable file, or other types of libraries. The function takes the DLL name as an argument. This means we just need to allocate some memory, write the path to the DLL, and set the starting execution point to the address of the `LoadLibraryA()` function, with the argument being the address of the memory that contains the DLL path. The main drawback of LoadLibraryA() is that it registers the DLL with the program, making it easy to detect (each program has a table of loaded DLLs). Additionally, the DLL is only loaded, not executed. * Jumping to DLLMain (or another entry point) An alternative method to LoadLibraryA() is to load the entire DLL into memory and determine the offset to the DLL entry point. This approach avoids registering the DLL with the program (stealth mode) and executes the DLL within the process. For detection, there are many ways to detect DLL Injection, but the most common approach is to check the process’s module list and look for memory regions with read-write permissions. # Sample Practice This part we will check the technique `T1574.002` of Atomic Redteam. We get start with this command line: ```powershell Invoke-AtomicTest T1574.002 ``` After that, we can see that `cmd.exe` is activated in a short time and `calc.exe` is called to appear. It's time to check process by some tools we can think of: `procexp` and `procmon`. First, let's check `procexp` and we see: ![image](https://hackmd.io/_uploads/BkCdI5BhA.png) It is important to know that `CalculatorApp.exe` and `calc.exe` are just the same. If you don't believe that, just check by testing your PC:smiley: So we seem to gain not much information with the first tool but it is worth. We could notice that when the command is executed, `cmd.exe` and `calc.exe` is called. With the filter in `procmon`, we can check only one of these two files. There is a high likelihood that `calc.exe` is called by `cmd` or `powershell`. So let's check `cmd.exe` first, but remember we should invoke again before applying filter. ![image](https://hackmd.io/_uploads/SJmBi9BhA.png) Above are the fields of processes. Let's try `Process Name is cmd.exe` and apply it. ![image](https://hackmd.io/_uploads/SyFSn5Hh0.png) Too much information and I realised that the operations related to registry is not important, so I just collect the operations that end with `start`, `create` and `Load Image`: ![image](https://hackmd.io/_uploads/S1kDyjH30.png) Pay attention to these above selected events. ![image](https://hackmd.io/_uploads/Bkyh1iSnR.png) It called `GUP.exe`, which we would check later. ![image](https://hackmd.io/_uploads/H1xMejShC.png) Hmmm seem like it called `GUP.exe` to execute `calc.exe` due to their consecutive time. ![image](https://hackmd.io/_uploads/S1D6esB3C.png) ![Screenshot 2024-09-04 155712](https://hackmd.io/_uploads/BJrGZiS2A.png) Meanwhile, I guess that `preloader.dll` loaded `calc.exe`. I think it's enough. Let's check files in folder `C:\AtomicRedTeam\atomics\T1574.002\bin` ![image](https://hackmd.io/_uploads/SyMuzoB20.png) Click on `GUP.exe` we see that `calc.exe` appeared. To analyse carefully, push them in `IDA` or `Ghidra`. ![image](https://hackmd.io/_uploads/B1A9vsr2R.png) I see `libcurl.dll` in the application’s directory, maybe it's suspect. ![image](https://hackmd.io/_uploads/HkxAMnH2R.png) Yay, it really load `calc.exe`. So we can conclude that `GUP.exe` is vulnerable to DLL Side-Loading, thus enabling the `libcurl.dll` to be loaded. Upon execution, `calc.exe` will be opened. Use this command to clear the process: ```powershell taskkill /F /IM calc.exe >nul 2>&1 ``` When it comes to `preloader.dll`, everything is very obvious and easy: ![image](https://hackmd.io/_uploads/BJmHunr2R.png) ![image](https://hackmd.io/_uploads/rJKzOnH3R.png) Utilizing the `dotnet_startup_hooks` environment variable, this method allows for registering a global method in an assembly that will be executed whenever a .net core application is started. This unlocks a whole range of scenarios, from injecting a profiler to tweaking a static context in a given environment. Use this clean up command: ```bash taskkill /F /IM calc.exe >nul 2>&1 ``` This way can be said manually. But from that, we can see it's all process starter or create new process. As I mentioned above in the [DLL search order hijacking](https://hackmd.io/UM0kiG3XTdiZTj-b-o8wgg?view#DLL-Search-Order-Hijacking), we can think of investigating eventcode 1, 7, 4688 in Splunk. Invoke it and see what happens: ![image](https://hackmd.io/_uploads/rkG5snH3A.png) To start, we check the structure of data and we focus on `EventCode` and maybe `cmd.exe` or `calc.exe`. After some trials, I use that query and see what I got: ```sql EventCode = 4688 cmd.exe| table _time EventCode Process_Command_Line ``` ![image](https://hackmd.io/_uploads/SJoz03r3C.png) Then we do it again with much shorter time.