Reflective Load
To begin, we’ll open the previous ConsoleApp1 C# project in Visual Studio.
We’ll create a new project in the solution to house our code
by right-clicking Solution ConsoleApp1’ in the Solution Explorer.
From the Add a new project menu, we’ll select Class Library,
which will create a managed DLL when we compile.
After clicking Next,
we’ll accept the default name of ClassLibrary1, click Create,
and accept the security warning about remote projects.
The process of creating a managed EXE is similar to that of creating a managed DLL.
In fact, we can begin by copying the contents of the Program class
of the ConsoleApp1 project into the new Class1 class.
We’ll copy the DllImport statements as-is,
then create a runner method,
with the prefixes public, static, and void.
This will serve as the body of the shellcode runner and must be available
through reflection, which is why we declared it as public and static.
Next we’ll copy the exact content of the Main method
of the ConsoleApp1 project into the runner method.
We’ll also need to replace the namespace imports
to match those of the ConsoleApp1 project.
With the C# code complete, we can compile it,
start our listener,
and copy the resulting DLL ClassLibrary1.dll
into the web root of our Kali Linux machine.
Once the file is in place, we’ll ensure that Apache is started.
In a new 64-bit session of PowerShell ISE on the Windows 10 victim machine,
we’ll use a download cradle to fetch the newly-compiled DLL.
We’ll use the LoadFile method to dynamically
load our pre-compiled C# assembly into the process.
This works in both PowerShell and native C#.
After the assembly is loaded,
we can interact with it using reflection through the GetType and GetMethod methods,
and finally call it through the Invoke method:
Executing this PowerShell results in a reverse Meterpreter shell,
but it will download the assembly to disk before loading it.
We can subvert this by instead using the Load method,
which accepts a Byte array in memory instead of a disk file.
In this case, we’ll modify our PowerShell code
to use the DownloadData method to download the DLL as a byte array.
With this change, we have successfully loaded precompiled C# assembly
directly into memory without touching the disk,
executed our shellcode runner and got our meterpreter shell.
Excellent!