About three years ago Google Project Zero’s researcher James Forshaw released the excellent DotNetToJScript project (https://github.com/tyranid/DotNetToJScript). If you’re not familiar, it introduced an interesting method to reflectively load a .NET assembly using native Windows scripting languages such as client-side JScript and VBScript. From an attacker’s perspective this opened a new door to obtain code execution, especially in constrained environments. Given that it’s been about 3 years since the project was released, many of the traditional antivirus vendors have caught up with detecting DotNetToJScript payloads. However, under the right circumstances you can still make use of this powerful tool to obtain code execution during your Red Team and Purple Team engagements.
Red/Purple Team Testing
I wanted to take a moment to discuss why you’d want to try using this project during your Red/Purple Team Testing. Once upon a time in early 2017, in my previous life, the internal Red Team I worked on was beginning to run up against fairly advanced detection. We performed weekly testing of our Blue Team, and those tests generally involved delivery of malware infected documents (maldocs) that dropped/downloaded a payload for execution. We were in the process of switching to Cobalt Strike, however staging was problematic. If we wanted to execute PowerShell during our weekly tests there was a really good chance we were going to be caught due to PowerShell log collection and analysis. Even if we performed obfuscated of PS one-liners there was a good chance it would be found quicker than we wanted. PowerShell downgrades got us half-way there, however the detection team was fast to update rules to catch any command line parameter variations allowing us to downgrade to PS v2.
We were already aware of the UnmanagedPowerShell project (https://github.com/leechristensen/UnmanagedPowerShell) created by Lee Christensen, and wanted to somehow integrate it into our deployment, but it wasn’t until DotNetToJScript came out that we had the EUREKA moment. Combining these two projects, in addition to heavy obfuscation with our custom maldoc generators, we were able to reflectively load a PowerShellRunner .NET assembly into memory and run a Cobalt Strike PowerShell one-liner to stage our payloads without ever executing the PowerShell binaries all from VBA!
Since we had built our PowerShellRunner assemblies against the .NET 2.0 runtime we were able to avoid the more advanced PowerShell event logs when we loaded Cobalt Strike with VBA. Although our Blue Team was pretty annoyed with us, they eventually implemented better PowerShell downgrade detection based on PowerShell Engine startup event logs, and we had to pivot again. By this point we had hired on the sharpest defender on the Blue Team, and he wanted to make his mark. With a little prodding and direction, he refactored our maldoc generation toolchain to directly inject a Cobalt Strike beacon into memory from VBA, using a .NET assembly and DotNetToJScript techniques.
Although we’re 3 years past the release of DotNetToJScript it’s still a very viable project for implementing execution payloads. Depending on the antivirus or EDR product you use, there’s chance that you can make use of simple payloads that can be executed with WScript/CScript. We’ve found in our Red/Purple Team engagements that if you’re utilizing Symantec/McAfee/Defender that it’ll be a challenge to obtain execution with JS/VBS/WSF scripting files. However, in many engagements where our clients have dropped traditional AV for just an EDR solution that a basic JScript/VBScript payload will yield execution very reliably. We won’t name names on which EDR vendors perform poorly with these test cases, but it’s safe to say that ALL EDRs we’ve tested fail at detecting/preventing malicious DotNetToJScript payloads, executed via WScript, CScript or both.
Please, if you’re an internal Red Team try to use this project to drive improvement in prevention/detection at your organization.
The first step to tinkering with this project is to download and build it. Although you can download a release version from GitHub I personally prefer to build from source whenever it’s available.
The first think you’ll want to do is open the solution file in Visual Studio.
You’ll note that the default build type is Debug. This shouldn’t get in the way of any testing, however I generally set Release builds since compilation options are configured for portability. We’ll configure for a Release build here, so that we can see how it’s done.
Now that we’ve changed the build type we can compile the project. If you want to be quick about it, you can type: CTRL+Shift+B. Otherwise you can step through the menu:
Assuming everything went well, this is what you should see in the Output pane for a successful build:
Now that we have our own copy built we can make ourselves a sample payload using the ExampleAssembly .NET assembly that was built during the project’s compilation. We’ll pop open a command prompt and move to the build output folder:
Then let’s take a quick look at the location of the ExampleAssembly directory’s location:
Now let’s look at DotNetToJScript’s options:
Although there are a lot of options we only need to use a few. You can use DotNetToJScript to build several Scriptlet variations, but for the sake of our testing we won’t need to worry about that. Instead we’ll use the following command to build ourselves a JScript payload using the ExampleAssmembly:
Excellent, now let’s open up a File Explorer window to our Desktop folder:
We see our test.js JScript file. Now we double-click to execute it with WScript:
And we have success! The ExampleAssembly simply loads a MessageBox with the title and text set to “Test”.
We’ve covered the basics on what DotNetToJScript is, and why you should still care about it. We’ve also seen that it’s pretty easy to get DotNetToJScript downloaded, built and tested. In the next blog on this topic we’ll modify the UnmanagedPowerShell project’s PowerShellRunner to use with DotNetToJScript. Stay tuned!