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.
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.
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.
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.
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.
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.
Now run the script in a disposable environment. Please note that the tool will actually run the script and can potentially infect the machine.
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.
The following screen shows the new PowerShell script created by evaluating the previous statement.
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.
Following the ‘if’ condition, the script will exit if the language pack is not Italian.
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.
PowerShellRunBox supports multiple executions of a command. The following shows the running of the s(tep) command 100 times.
The following shows the URLs extracted from the script.
The downloaded image looks like just a normal image file, but it actually contains pixels with next stage script information.
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.
From inside the loop, you might want to step out of it using the ‘o’ command.
The following is a script block that will reconstruct the next stage script code.
The MICd variable contains reversed strings of the next stage code.
Checking geolocation and cultural information
Use https://ipinfo.io/country to determine the location of the machine the script is running on.
Check the language settings again using the Get-Culture function.
Decoded C&C URL
Here’s the code to download the final PE payload from a C&C server.
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.
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.