DotNetToJscript
Now that we’ve discussed the basics of Visual Studio,
let’s introduce C# code into our Jscript.
In 2017, security researcher James Forshaw
created the DotNetToJscript project
that demonstrated how to execute C# assembly from Jscript.
In this section, we’ll use this technique to create our in-memory shellcode runner.
First, we need to extract the version stored locally in the tools folder
on the Windows 10 development machine,
and then copy it to our Kali Samba share,
and open it in Visual Studio.
When opening the Visual Studio solution from a remote location,
a security warning prompts us asking us if we really want to open it.
Once we’ve opened DotNetToJscript in Visual Studio,
we’ll navigate to the Solution Explorer and open TestClass.cs
under the ExampleAssembly project.
We’ll compile this as a .dll assembly,
which we’ll execute in Jscript.
This simple project will display a “Test” message box.
Jscript will eventually execute the content of the TestClass method,
which is inside the TestClass class.
In this case, we are simply executing the MessageBox.Show method.
Notice that the Solution Explorer lists a second project called DotNetToJscript
that converts the assembly into a format that Jscript can execute.
At this point, let’s switch from Debug to Release mode,
and compile the entire solution.
When the solution is compiled, we need to move some files to get DotNetToJscript
to work correctly.
We’ll navigate to the DotNetToJScript folder
and copy DotNetToJscript.exe
and NDesk.Options.dll
to the Tools folder on the Windows 10 development machine.
Then we’ll go to the ExampleAssembly folder,
and also copy ExampleAssembly.dll to the Tools folder.
Note that these .dll files must be in place
whenever we execute a DotNetToJscript program.
After copying the required files,
we’ll open a command prompt on our Windows machine,
and navigate to the Tools folder.
We need to set a few options at runtime.
First, we’ll specify the input file,
which in our case is ExampleAssembly.dll.
Next, we’ll specify the script language to use,
in this case, JScript,
along with the .NET framework version.
On the newest versions of Windows 10,
only version 4 of the .NET framework is installed and enabled by default,
so we’ll specify v4.
Finally, we’ll specify the output file,
in our case a Jscript file.
Now that the file is created,
we can double-click it to run it.
This displays our simple popup.
Let’s examine the Jscript code generated by DotNetToJscript
to get an idea of what, exactly happened.
We’ll open demo.js in a text editor to view this code.
The code begins with three functions:
Let’s examine each of these.
The setversion function configures the Windows Script Host
to use version 4 of the .NET framework.
The debug function is empty
since we did not specify the debug flag when invoking DotNetToJscript:
Finally, the base64ToStream function is simply a Base64 decoding function
that leverages various .NET classes through ActiveXObject instantiation:
Following the helper functions, we find the main content of the script.
Let's analyze this code.
First, a Base64 encoded binary blob
is embedded into the file.
This is our compiled C# assembly.
Next, the name of the class inside the compiled assembly
that we want to execute is specified.
In our case it’s named TestClass.
After specifying the name of the class, the heart of the script begins.
First, the .NET framework version is set,
and the blob is Base64 decoded.
Next, a BinaryFormatter object is instantiatied,
from which we call the Deserialize method.
At this point,
the d variable contains the decoded
and deserialized ExampleAssembly.dll in memory.
To execute the relevant method inside the assembly,
we’ll use the DynamicInvoke and CreateInstance methods.
DynamicInvoke accepts an array of arguments
but no arguments are required by the constructor of the “TestClass” class.
We solve this by creating an array assigned to the "al" variable,
then add an undefined object to keep it empty
This creates an empty array which is passed to DynamicInvoke.
Finally we execute the constructor through CreateInstance by supplying its name,
which is stored in entry_class.
Now, thanks to DotNetToJscript,
we have the framework we can use to easily convert any C# code
into a format that can be executed from a Jscript file.
This brings us closer to having the ability to execute Win32 APIs.