PowerShellRunBox: Analysing PowerShell threats using PowerShell debugging

By on 23 Oct 2019

Category: Tech matters

Tags: , ,

Blog home

Malicious PowerShell scripts are one of the most prevalent threats these days. There are many Advanced Persistent Threat (APT) actors that have used PowerShell as a delivery or migration mechanism. Commodity malware has been using PowerShell for a long time, too. In many cases, Microsoft Office macro malware uses PowerShell scripts to proceed with further attacks. The MITRE ATT&CK matrix has a good summary of these trends. There are attack kits like PowerShell Empire and PowerSploit that use PowerShell as their main implementation language.

There are many reasons why PowerShell is so popular among attackers. Windows platforms since Windows 7 have PowerShell installed by default. PowerShell is very powerful in interacting with Windows subsystems. Most of the usual malware activities like dropping files and running them, and communicating with Command and Control (C&C) servers are easily achievable with PowerShell. Some attack frameworks support file-less operations by loading downloaded executables reflectively on the memory. With these aspects, PowerShell is a perfect tool to perform file-less living-off-the-land attacks. Traditional defence mechanisms of the anti-malware industry are very focused on file-based threats and still have a large technology gap in covering this new file-less trend.

The only problem with PowerShell from the attackers’ perspective is that the source code is revealed easily. To avoid easy analysis and detection, they put a lot of effort into obfuscating PowerShell scripts. They also split their scripts into many components and deliver them one by one; delivering the final threat after multiple obfuscated PowerShell executions. These tactics work very well in many cases. Analyzing and understanding PowerShell-based threats is very time-consuming work in most cases due to these facts.

Through this article, we are going to analyse one of the most typical cases where obfuscation and payload splitting are used and will talk about a new approach that can help analysts perform their work more effectively.

Obfuscated PowerShell code

The following code shows one of the PowerShell threats that are delivered through the Office Excel VBA script. The behaviour of this threat is well observed with sandbox technology. For example, through an any.run session, you can observe how Excel runs the PowerShell script to run further attacks. A PowerShell instance is used after setting up an obfuscated script as a Windows environment variable from the command prompt.

Figure 1 — Process tree of the threat.

The PowerShell script code is heavily obfuscated and manually de-obfuscating this threat can take sizable efforts from human researchers to fully understand these kinds of threats.

Figure 2 — Heavily obfuscated PowerShell code.

There are many elements that make this script very hard to analyze. First, it splits PowerShell class and function names into multiple strings and combines them on the fly. Secondly, it uses base64 encoding to encode next stage scripts and randomize their order to prevent brute-force decoding of the script. Thirdly, it uses compression to prevent partial decoding of the encoded base64 code. Also, it uses multiple variables to split logic in different locations of the code.

Introducing PowerShell Debugger

Fortunately, PowerShell has a debugger functionality embedded with it. This article has a good pointer in using debugging features with PowerShell ISE. It is possible to use ISE for analyzing malicious PowerShell code. But, in most cases where you want some level of automation, a custom PowerShell debugger might work better.

Introducing PowerShellRunBox

You can embed a PowerShell debugger in a standalone program and register your own StopEvent callbacks to implement some automation features. We released PowerShellRunBox, the project that uses PowerShell debugging, to provide some convenient features for analyzing highly obfuscated PowerShell code. We are going to share how this new tool can help analyze highly obfuscated PowerShell code.

Overview of the obfuscated PowerShell script

The overall infection flow looks like the following. It has three checking routines (yellow blocks) where it makes sure the threat is run inside the Italian Windows language environment.

Figure 3 — Flow of the malicious PowerShell script execution.

It does extra checks using https://ipinfo.io/country to check if the public IP address of the machine and network belongs to Italy. Basically, it has multiple levels of language packs and geolocation checks. It will not download the next stage payload when it doesn’t find it running in a specific region with a specific language pack.

This is a huge problem for dynamic analysis. For example, session run-through detonation services like any.run will not be complete unless it runs on the very specific environment the malware is expecting. Without analyzing the PowerShell code itself, you will not have the information in the first place. This can be one of the tactics for the attackers to evade dynamic analysis.

Running PowerShellRunBox

In many cases, we need to understand micro-behaviours of the PowerShell script mainly because some scripts perform a lot of anti-analysis. Those behaviours can’t be observed by observing macro behaviours like file or process creation. PowerShellRunBox can help with this problem by giving you a detailed look into how the script code runs.

To prepare the debugging environment, first replace the PowerShell command with PowerShellRunBox in the script.

Figure 4 — Modifying command line to run PowerShellRunBox.

Now run the script in a disposable environment. Please note that the tool will actually run the script and can potentially infect the machine.

Figure 5 — Initial breakpoint.

The following screen shows the ‘mZug’ variable set by the first statement of the script. The PowerShellRunBox will show the modified or newly created variables automatically through the debugging session.

Figure 6 — New or modified variables will be automatically shown.

Script evaluation

The following screen shows the new PowerShell script created by evaluating the previous statement.

Figure 7 — Newly evaluated script.

Forcing variable assignment

The script has an ‘if’ condition that checks for the locale of the PowerShell environment. You can observe that ‘RAd’ variable is set to ‘en-US’ here as we ran the script on an English-language environment.

Figure 8 — ‘If’ condition to check if the language is Italian.

Following the ‘if’ condition, the script will exit if the language pack is not Italian.

Figure 9 — Exit if the locale doesn’t match the Italian language set.

After iterating through multiple debugging sessions, we can come up with variable names that the malicious code checks. We can use the Config.json file to set the variables to be replaced on the fly in the debugging session. This automation feature can save you a lot of time.

Figure 10 — Config.json to set up variables.

Repeating commands

PowerShellRunBox supports multiple executions of a command. The following shows the running of the s(tep) command 100 times.

Figure 11 — Repeating ‘s’ command 100 times.


The following shows the URLs extracted from the script.

Figure 12 — Encoded image file URLs.

The downloaded image looks like just a normal image file, but it actually contains pixels with next stage script information.

Figure 13 — Encoded image file.

The following code shows the loop where it decodes the next stage PowerShell script from the image — downloaded from image services like imgbox.com or imgur.com.

Figure 14 — ‘For’ loop.

From inside the loop, you might want to step out of it using the ‘o’ command.

Figure 15 — Debugger commands — use ‘o’ command to get out of the loop.

The following is a script block that will reconstruct the next stage script code.

Figure 16 — Next stage code assigned to the MICd variable.

The MICd variable contains reversed strings of the next stage code.

Figure 17 — MICd variable.

Checking geolocation and cultural information

Use https://ipinfo.io/country to determine the location of the machine the script is running on.

Figure 18 — Determining location.

Check the language settings again using the Get-Culture function.

Figure 19 — Getting culture information.
Figure 20 — Our configuration replaces Ee variable to ‘ita’

Decoded C&C URL

Here’s the code to download the final PE payload from a C&C server.

Figure 21 — Stage 3 PE payload URL.


We went through the debugging session for one of the most complicated malicious PowerShell scripts. Manually analyzing these threats takes a huge amount of time and valuable effort. There are not many sandbox or detonation technologies that understand PowerShell internal-level behaviours such as language checks or steganography actions. PowerShellRunBox can be used to tackle this problem and potentially we can add more automation features as we go, for example, automatic loop detection and code coverage brute-forcing with automatic variable modification. It has good potential to be used for automatic threat analysis.

Matt Oh is a cybersecurity professional who worked for Microsoft for the last decade before building his own security firm – DarunGrim. He has focused on building cutting-edge protection mechanisms to detect and deter malware and exploits.

This article originally appeared on the Darun Grim blog.

Rate this article

The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.

Leave a Reply

Your email address will not be published. Required fields are marked *