When developing WMImplant, I wanted to ensure I would have some of the same capabilities on a Device Guard (now Windows Defender Application Control) protected system as I would on a non-protected when utilizing Beacon or Meterpreter. WMImplant is a stepping stone for creating the same capabilities, but also presented some of its own engineering problems since it exclusively utilizes WMI. A feature that I wanted to build-in is the ability to run PowerShell scripts remotely against multiple systems in a domain, and my first problem was determining what way I would do that.
The command-line interface does allow you to easily script WMImplant, or use built in functionality to run a command across a large number of systems. This post will demo how WMImplant can run PowerShell scripts, receive the output from them, and show how to run a demo PowerShell script against multiple systems.
How it Works
I like to think of executing a program or command via WMI as “blind execution”: we can see that WMI spawned a process on a system, but you can’t get any output. I wanted to change this to be able to leverage WMI to not only spawn processes, but get the output if we want it! WMImplant follows multiple steps to accomplish this task:
- It queries the target system’s DebugFilePath property value to capture the original contents
- It encodes the command (or script in this case) and stores in the target system’s DebugFilePath property, overwriting the original value
- It spawns powershell.exe on the target system. The PowerShell process collects the value of its DebugFilePath property, decodes it, runs the decoded code, stores the results in a variable, re-encodes the variable, and stores the encoded results in the DebugFilePath property
- It queries the target system’s DebugFilePath property to received the encoded results, decodes the results, and displays them in the console
- It then writes the original value of the DebugFilePath back to the targeted system
Running PowerShell Scripts
The first step to running PowerShell scripts across multiple systems is to generate a file containing all systems you are targeting. The easiest way is adding each hostname or IP on a new line in a text file. WMImplant will accept targets via the pipeline, meaning that once you have all your targets in a text file, you can use Get-Content to capture the file contents and pipe them into WMImplant.
For example, let’s write a sample PowerShell script where the only action it takes is writing output to the console.
Then, we need to generate a command-line command instructing WMImplant to run the PowerShell script across multiple systems. I briefly touch on using gen_cli in my first post on post-exploitation with WMImplant. We will need to run gen_cli, provide the information that WMImplant requests, and copy the command-line output.
Once WMImplant generates the command, it’s as simple as copy pasting it into the terminal and receiving your results!
You can follow this process to run any PowerShell script across multiple systems, such as custom scripts, Invoke-Mimikatz, Invoke-NinjaCopy, and so on. I hope that this blog posts helps, and if you have any questions, don’t hesitate to contact us here at FortyNorth Security!