In the previous blog post, we discussed how payloads facilitate malicious communications and how an attacker can gain control of a system after successfully executing the payloads and beacons. We used a reverse_tcp communications channel facilitated by the Meterpreter payload (from the Metasploit Framework).
This post will focus on understanding more about the distinct types of payloads and examples of the memory manipulation techniques they may employ.
Malware has become more sophisticated in composition and execution — especially in contrast to the days of simpler viruses, like the Creeper program in the early seventies. For threat actors motivated primarily by clandestine aims, staying under the radar to persist in a network undetected for an extended period is typically a top focus. Therefore, they will employ corresponding techniques such as decoys, encoding, obfuscation, encryption and mimicking to achieve the desired level of operational security.
There are several executable formats available to a threat actor. The attacker’s choice depends on the initial attack vectors and subsequent post-exploitation actions. Here are some of the Metasploit Framework’s executable and transform formats.
As demonstrated in part one, the beacon or payload is the implant on a victim machine or network that gives an attacker an entry and then foothold. It is an important part of the malware arsenal and overall attack lifecycle, allowing the threat actor hands-on access to pursue further malicious activity.
When it comes to the actual broad categorization, a payload may either be “staged” or be “stageless.” A threat actor may pick one over the other depending on several factors, chief of which may be operational security considerations.
What Are Staged Payloads?
Staged payloads break down the distinct phases of an attack, often using multiple payloads phases that a single payload would have otherwise performed. These payloads are typically broken down into a ”stager” (initial payload or beacon) executable and a ”stage” (main payload) executable.
A stager is a small executable that is an initial payload. It is a relatively small piece of code that is executed to prepare for a much larger and more capable payload known as the stage payload. This means that “the stager sets the stage.” A stager will typically be part of some exploit code when the initial entry leverages a vulnerability. Here, the exploit code will successfully exploit the target vulnerability and then run the stager code (payload). The stager then kicks into action.
The stager’s primary task is to execute successfully without detection, reach back out to the attacker infrastructure to download the desired main payload, and then set up the system to execute that payload. The downloaded stage or larger main payload can be one or more payloads depending on the capability required by the attacker. Once the stage is downloaded, the stager then passes execution control to continue the malicious activity.
In the case of a vulnerability exploit, the initial exploit program does something similar for the stager as the stager does for the main stage payload, in terms of resource allocation on the compromised system. It will follow a pattern similar to this:
The example below shows a staged payload as a Windows executable.
Staged payloads accommodate for scenarios where there may be system-related constraints, such as disk and memory space, when it comes to payload delivery and execution — as in the case of shellcode used to exploit a buffer overflow vulnerability.
What Are Stageless Payloads?
The opposite of staged payloads is stageless payloads. Stageless payloads are self-contained and usually much larger than staged payloads. They typically combine all the required capabilities of an attacker into one executable.
Here, there is typically no need for an initial payload (stager) that downloads the main payload (stager). Once the stageless payload is executed, it will have all the necessary capabilities to perform malicious actions, such as memory injection, calling back to the attacker infrastructure and delivering a shell for the attacker.
The example below shows a stageless Meterpreter reverse tcp payload as a Windows executable.
The decision on what type of payload to use as part of a malicious campaign is known as the “operational security considerations” for that threat actor. The type of corresponding attacker infrastructure supporting the malicious campaign is partly influenced by these considerations.
Staged vs. Stageless Payloads
Metasploit staged payloads have the forward-slash symbol ( / ) after the word Meterpreter. The screenshot below shows examples of Windows staged Meterpreter payloads.
Stageless payloads employ the underscore symbol ( _ ) after the word Meterpreter. The screenshot below shows examples of Windows Meterpreter stageless payloads.
And the example below shows both categories of payloads.
Stageless payloads are self-contained and do not require the extra step of sending a stage (main payload) to the victim machine once the malware makes a callback to the attacker infrastructure. Notice in the screenshot below that after the reverse TCP handler starts, the next step is to open a hands-on Meterpreter remote shell session to the victim machine straight away — without the need to send any further payloads such as a stage.
From the screenshot below, we can see that there is the extra step of sending the stage after the stager makes a callback to the attacker infrastructure: “sending stage (175174) to 203.0.113.1.”
Another difference between staged and stageless is the size of the payloads. In the screenshot below, the stageless payload (meeting_update_stageless.exe) is much larger at 245KB compared to the staged initial payload (web1_meeting_update.exe) at 73KB.
What is Shellcode?
Shellcode is a malicious code that attempts to hijack the normal flow of a running program in computer memory. It then redirects the flow so that the malicious code is executed, instead of the normal program, giving the attacker a shell or hands-on access. These are often beacons or payloads in the form of low-level programming code or a machine code combined with an exploit. Exploits are pieces of low-level or native code that successfully leverage a vulnerability.
Exploited vulnerabilities often involve a buffer overflow in an application’s memory where the attacker has overrun the allocated memory to redirect normal program flow. A successful exploit will then lead to the execution of a payload, which is the malware.
In its purest forms, Shellcode will be native or assembly code commonly used in memory-related exploits.
The example below shows Powershell (ps1) shellcode.
This particular example uses a Windows Dynamic Link Library (DLL) injected into memory via a reflective loader. The shellcode is generated in alphanumeric form. Once successfully executed, it can connect back to the attacker via a reverse DNS TCP session generated from the Metasploit Framework.
The choice of delivery mechanism, the type of exploit, and the vulnerable target system all go to determine the choice of beacon or payload tied to the attack. The exploit is used to take advantage of a vulnerable application before gaining access to the underlying operating system. In such a case, specific code for the corresponding application may be used (e.g., PHP or ASP for web server front-end applications).
There are some important considerations and characteristics to ensure successful Shellcode execution and maintain high operational security.
The code must:
- Have all the instructions needed to execute the desired shell while still being relatively small in size.
- Be “position independent” in memory — this is crucial since it is often not possible to know where it will be loaded in the target vulnerable process’ memory beforehand.
- Not contain anything that could cause potential errors or cause the entire process to crash; for example, due to null characters (0x00).
- Be capable of piggybacking on some existing memory allocation using some injection techniques — code or reflection injection.
From this point, the attacker will then need to select the appropriate post-exploit executable type to execute on the target system, such as EXE or DLL for Windows, ELF for Linux, and APKs for Android. Again, memory-only post-exploitation techniques are preferred to increase operational security.
What is Code Injection and DLL Injection?
DLL injection is the process of running code (DLL) in the context of another process. Meterpreter payloads use DLL injection techniques for stealth and evasion mechanisms.
In Windows, a Dynamic Link Library or DLL (“Shared Library” in Linux) is a piece of code stored as a shared library file. This means that it can be used by different computer programs as and when they need it. The operating system (in this case, Windows) handles writing and loading the library, which is done at runtime. A program can simply call or reference the required DLL file to use the code contained within it.
This is useful for programmers because they only write code once, compile and store it as a shared library or DLL, then use it whenever needed and by multiple programs.
The main difference between a DLL and an EXE file is that a DLL cannot run independently. It needs a program like an EXE to call or reference and then run it. The following example shows DLL files in a Windows operating system, which are typically stored in the C:\Windows\ WinSxS folder (WinSxS stands for Windows Side-by-Side).
The capabilities of DLLs also make them very useful for threat actors. Code Injection at the basic level involves an attempt by one process (malicious) attaching (or obtaining a handle) to a remote process (victim process). It then allocates enough memory or changing page permissions in the victim process to run new code such as a DLL, after which copying (injecting) the DLL malicious code into the new or already running victim process' memory space.
A new thread, which is how processes execute specific tasks, is then started in the victim process to run the instructions contained in the injected code or DLL.
A thread shares the same memory space as the process that started it, whereas different processes have distinct allocated memory spaces, especially in cases where they do not share any variables. This is enforced by the operating system. However, operating systems provide mechanisms for processes to communicate when required using Inter-Process Communication (IPC), such as Pipes (named or anonymous), Sockets, Semaphores, Shared Memory, and Message Queues.
In Windows operating systems, code injection involves using legitimate Windows APIs and functions for malicious aims. For example:
- OpenProcess is used to gain a handle into a process,
- VirtualAllocEx then facilitates allocating enough memory in that remote process or,
- VirtualProtectEx may be used to override memory (page) permissions, and then
- WriteProcessMemory writes the malicious code, such as a DLL into the victim process.
- CreateRemoteThread, RtlCreateUserThread or NtCreateThreadEx is used to create a new thread (which is how processes execute specific tasks) and execute the malicious capability, such as stealing credentials or executing ransomware.
Loading a DLL in Windows requires calling the LoadLibraryA or LoadLibraryExA functions, which is part of libloaderapi.h. These functions, as Microsoft puts it, “load the specified module into the address space of the calling process.” Using LoadLibrary to load a DLL means the DLLs must be loaded from disk.
However, using the reflective DLL injection technique, a DLL can be loaded directly from memory, a capability not currently offered by LoadLibrary. A threat actor can use reflective DLL injection to self-load their malicious code entirely in memory without the need for invoking the native Windows loader on disk. Here, they utilise a custom loader instead of the Windows LoadLibrary.
Attackers may also use other injection and process manipulation techniques, such as:
- Process hollowing — Where malware will start a victim process in a suspended state.It then hollows out the memory to make room for new code, changes page permissions, injects malicious code, and resumes the process to execute the injected malicious code.
- DLL side-loading — Where a legitimate and often older vulnerable Windows program (victim process) is forced into loading a malicious DLL, which is deliberately named the same as a legitimate one expected by the victim and placed in the same directory (side by side) as the vulnerable program. The victim program’s process will look in its immediate folder first to locate the renamed (impersonated) malicious DLL. This technique capitalises on the DLL search order used by the Windows loader to succeed.
These techniques attempt to make malicious activity appear legitimate, thereby evading detection to persist on a compromised system.
From the process manipulation techniques discussed in part one of this series, we can see below that the migration of the original malicious web1_meeting_update.exe involved some code injection.
In this example, the malicious payload started (spawned) a completely new notepad.exe process as the desired victim process to inject code. The original malicious process (PID 2472) is then injected or migrated into the new notepad.exe victim process (PID 1768).
Notepad.exe is a trusted Microsoft process, and as such, this gives the attacker the ability to disguise the original malicious-looking process to a more trusted one. Notepad.exe is a basic Windows text editor that does not need to call (reference) any Windows API, function or DLL required for network connection — which in our example, the malicious process executed.
Dynamic analysis is required to detect the injection happening in memory. Application dependency mapping is also needed to detect the suspicious network communications of the text editor, in this case notepad.exe process, making a network connection.
Following on from part one of this blog series, we have looked some of the categories and types of payloads that a threat actor may use and why they may decide to use one type over another.
Most threat attackers will go to great lengths to ensure that they have a successful initial entry, maintain persistence, and avoid detection. We have seen so far that the combination of tools, techniques and procedures means that an equally capable combination of security tools and procedures is needed to prevent a successful attack — or more likely to assume breach and prevent an initial cyber incident from becoming a major breach.
In the final part of this series, we will discuss some more techniques and capabilities and, most importantly, explore analysis and mitigation.