Today, we are going to dwell on a Microsoft tool, the infamous rundll32.exe, which allows you to load and execute code. It is often used by adversaries during their offensive operations to execute malicious code through a process which we will explain in detail.
Rundll32.exe is a Microsoft-signed binary used to load dynamic link libraries (DLLs) in Windows. It is native to Windows and present in both 32 and 64 bit versions, respectively present in these places:
C:\Windows\System32\rundll32.exe |
Here are the signing details:
On the one hand, rundll32.exe is an executable signed by Microsoft which is natively present on all Windows systems; on the other hand, it is also very flexible and efficient for loading code into memory, acting as a proxy for this purpose. Moreover, because rundll32.exe benefits from a certain degree of trust, it could be a possible AppLocker and Software Restriction Policies (SRP) bypass.
Last but not least, rundll32.exe is also able to help to dump the memory of processes, such as the LSASS (Local Security Authority Subsystem Service) process to retrieve credentials, which we will demonstrate.
For these reasons, it is a very interesting and frequently used tool by adversaries to proxy execution of arbitrary malicious code and dump LSASS memory. This technique is also mapped and described in the MITRE ATT&CK™ Enterprise framework, rundll32.exe has its own sub-category, as below:
Tactic |
Defense Evasion |
Technique ID |
T1218 .011 |
Technique Name |
System Binary Proxy Execution |
Sub-technique Name |
System Binary Proxy Execution: Rundll32 |
Defense Bypassed |
Anti-virus, Application control, Digital Certificate Validation |
Although rundll32.exe has frequent and undeniable legitimate use, it is also taken advantage of by many attackers, ranging from state-affiliated groups (APTs) to cybercriminal groups to proxy execution of malicious code.
Some of these threat actors are among the most sophisticated attackers around and still rely on rundll32.exe during their operation. Just to cite a few, we can have:
We could also note that tools such as Cobalt Strike can use rundll32.exe to load DLL from the command line. This list could be much longer but the idea is to briefly summarize the importance, dangerousness and diversity of these groups that rely on rundll32.exe, so it is important to understand its mechanism to detect it.
Microsoft does not provide detailed information about rundll32.exe, but they mention the syntax below:
The syntax is not perfectly correct, you have to specify an entry point into the dynamic-link library (DLL) as below (otherwise nothing will happen):
rundll32.exe <DLL PATH>,<DLL Entry Point> |
Note that <DLL PATH> could be both local and remote when the DLL is hosted on an accessible share, using UNC (Universal naming convention) paths in the second scenario.
Even if the entry point does not exist, the system will calls the DllMain function with the DLL_PROCESS_ATTACH value first and the relevant code will be executed followed by an error message because of the missing entry point.
Indeed, rundll32.exe process uses the LoadLibraryExW function which calls DllMain (DLL’s entry point) and load the DLL into the virtual address space of the rundll32.exe process as we notice below:
Analyzing the stack, we notice a LoadLibraryExW call with:
To better understand these values, let’s have a look at LoadLibraryExW function’s (from libloaderapi.h) syntax:
HMODULE LoadLibraryExW( // From this example: |
The following parameters are used:
Know that LoadLibraryExW is theoretically able to load a DLL module without calling the DllMain function of the DLL but here, rundll32.exe is using dwFlags set to 8 which isn’t inducing this behavior. The code is equivalent to:
hLibModule = LoadLibraryExW(<DLL PATH>,(HANDLE)0x0,8); |
Note: As per Microsoft API documentation, when rundll32.exe calls the DllMain function with any specific entry point, (i.e. a value other than DLL_PROCESS_ATTACH), the return value is ignored. If the return value is FALSE when DllMain is called during process initialization, the process terminates with an error and GetLastError is called to provide extended error information.
We will now create a simple 32-bits C++ DLL named RUNDLL32_TEST.dll which will execute calc.exe once the DllMain function is called with the DLL_PROCESS_ATTACH value and we will create a specific exported entry point to execute cmd.exe. Let’s also provide debug information using MessageBox:
#include "pch.h" |
It is important to note that even when targeting a specific entry point (DLL-exported function), the code within the DllMain function from DLL_PROCESS_ATTACH will still be executed.
Note: This behavior was previously discussed, it is related to the dwFlags set to LOAD_WITH_ALTERED_SEARCH_PATH when calling LoadLibraryExW from rundll32.exe (this flag is not under control).
With our DLL, we will have two applications executed (calc.exe and cmd.exe) and two message boxes in this scenario when using the SpecificEntryPoint.
Finally, please note that it is not a good practice to call CreateProcess within DllMain, as it could lead to improper synchronization and cause an application to deadlock as creating a process can load another DLL.
Let’s first execute calc.exe (DllMain function with the DLL_PROCESS_ATTACH value and a fictive but mandatory entry point):
rundll32.exe RUNDLL32_TEST.dll,ThisEntryDoesNotExists |
This command, targeting a fictive entry point (non-existing DLL-exported function), will result in the execution of calc.exe because of the previously mentioned point.
Note: Without an entry point, even non-existing one, the DLL will not be loaded (despite what Microsoft’s documentation describes).
Now, let’s play with our DLL-exported function named SpecificEntryPoint to execute cmd.exe using the following command:
rundll32.exe RUNDLL32_TEST.dll,SpecificEntryPoint |
We previously made an observation about LoadLibraryExW which was important as the specified module is loaded into the address space of the calling process (rundll32.exe), hence we could recover loaded modules inspecting the thread’s stack as we can see below:
As result, we could notice a spawned cmd.exe with non-existing parent because the rundll32.exe process (PID 1844) is terminated and cmd.exe process (PID 10904) was created as a new and independent process:
However, thanks to the Cybereason Defense Platform, we could examine the history, all loaded modules and all other relevant information and also visualize the processes tree to notice that rundll32.exe is the parent of cmd.exe:
This example isn’t malicious by itself therefore we wouldn't raise a MalOp™ for this execution, nevertheless, all relevant context and information are stored and accessible.
We have seen that rundll32.exe is a powerful asset for adversaries to proxy execution of arbitrary and malicious code. This binary has another ace in the hole, it could leverage comsvcs.dll (a Microsoft-signed DLL) which exports a function called MiniDumpW that rely on MiniDumpWriteDump to dump lsass.exe (Local Security Authority Subsystem Service) process memory to retrieve credentials.
MITRE ATT&CK Mapping: This technique is named "OS Credential Dumping: LSASS Memory" and has the ID T1003.001.
The syntax is as below:
rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump <LSASS PID> <DUMP PATH> full |
Where <LSASS PID> is the process ID of LSASS and <DUMP PATH> the output to be written. Note that this requires Local Administrator or SYSTEM privileges.
Example:
We demonstrated that rundll32.exe, which is a signed Microsoft binary, helps to proxy execution of arbitrary and malicious code and dump credentials.
Anything else, please? Of course! This binary is also able to:
You can refer to the LOLBas projects for further information and examples.
Thanks to our advanced AI-powered technology, we offer the perfect alternative to manually triaging and investigating a flood of alerts full of false positives: the Cybereason MalOp—an interactive graphical display of the full malicious operation from root cause. Instantly see all elements of an attack correlated across every impacted asset with the option for automated or one-click remediation, reducing investigation periods by as much as 93% so Defenders can eliminate threats in a matter of minutes rather than days.
Indeed, on the one hand, we already noticed that Cybereason is able to avoid false positives about benign use of rundll32.exe, using our test DLL to spawn another Windows binary which is not causing any harm to the system:
In the above scenario, such a technique isn’t dangerous, but below we demonstrate how Rundll32.exe can be abused.
Note: For the following tests, we configured the EDR with features and options in "detection" mode only to demonstrate detection capabilities without immediately blocking the attacks ("prevention" mode).
However, Cybereason will – of course – detect malicious behaviors of rundll32.exe and trigger active MalOps when it is relevant. For example, we demonstrated a technique when adversaries abuse rundll32.exe and comsvcs.dll to dump LSASS memory.
The Defender can leverage the MalOp™ to quickly ascertain all relevant information about the attack:
The Defender is then able to explore the process tree to hunt for suspicious activities:
To continue our examples, we could now create a malicious DLL using msfvenom to initiate a reverse shell to an adversary-controlled system. We will select a staged Reverse TCP Meterpreter payload and name it sample.dll:
Let’s now execute the DLL using rundll32.exe:
rundll32.exe C:\Payloads\sample.dll,XYZ |
A MalOp is created upon execution of this DLL to notify the Defender:
Note: The DLL is injecting a Meterpreter payload in Memory using Reflective DLL Injection technique, hence the reference to the “Module Injection” within the MalOp.
The Defender is well alerted and then able to explore the process tree to continue the hunt:
The Defender can proceed with additional adversary hunting from the process tree where we notice floating modules which are indicators of Reflective DLL Injection (Delivering Meterpreter):
We notice a machine with IP 10.160.155.26 (victim) connecting to another machine with IP 10.160.201.220 on port TCP/8080. This corresponds to the reverse Meterpreter (TCP) payload we created (sample.dll) and executed using rundll32.exe:
Let's take a look at another technique to execute VBScript and spawn a PowerShell prompt:
rundll32.exe vbscript:"\..\mshtml,RunHTMLApplication "+String(CreateObject("WScript.Shell").Run("powershell.exe"),0) |
Even though powershell.exe is a legitimate Windows binary, this indirect execution is still very unusual and suspicious because it could be used by adversaries as a roundabout execution means.
Thanks to our Behavioral Execution Protection feature, it is correctly marked as suspicious (unlike the cmd.exe and calc.exe executions we have previously seen, if you do remember):
The queries provided in this section can be used to hunt for possible malicious rundll32.exe processes. First of all, the following query provide all instances of rundll32.exe (including non-malicious ones), to have an overview of activities:
/#/s/search?queryString=0<-Process"elementDisplayName:)rundll32.exe"&viewDetails=false |
Result:
Then, it is possible to refine and limit the search to suspicious occurrences, you can filter on Has Suspicion is True and/or Has Malops is True with the query below or using the user interface:
/#/s/search?queryString=0<-Process"elementDisplayName:)rundll32.exe |
It is also possible to extend your query and hunt for outgoing connections with the query below (or using the user interface to graphically build the query):
/#/s/search?queryString=2<-Process"elementDisplayName:)rundll32.exe,hasOutgoingConnection:true"->connections->remoteAddress&sorting=elementDisplayName&sortingDirection=1&viewDetails=false |
Result:
We notice the remote IP 10.160.201.222 which is the adversary-controlled machine that received the Meterpreter reverse shell from the victim machine.
In the real world, this IP address could be used as a pivot (or “IoC” for indicator of Compromise) to pursue the Incident Response (IR) process and hunt for other malicious activities related to this specific address.
Cybereason is dedicated to teaming with Defenders to end attacks on the endpoint, across enterprise, to everywhere the battle is taking place. Learn more about the AI-driven Cybereason Defense Platform here or schedule a demo today to learn how your organization can benefit from an operation-centric approach to security.