I will never forget being in Redmond when Microsoft announced PowerShell to the world. PowerShell, which was at that time called Monad, was to be a new administrative tool for Windows. During the question-and-answer portion of the event, I told the panel that in spite of its potential as a system’s management tool, Monad sounded like a malware author’s dream come true. I then went on to ask what Microsoft was doing to keep Monad from being exploited. I have to admit that I can’t really remember the answer that I received, aside from the fact that it contained vague references to built-in security.
About a decade has passed since that press briefing, and Monad has evolved into Windows PowerShell, which is baked into every modern Windows operating system. However, my question still remains: What is to stop PowerShell from being used in the creation of malware?
If you were to ask Microsoft this question, the answer would probably reference execution policies. For the uninitiated, execution policies are a PowerShell mechanism that is designed to prevent an unauthorized script from running.
Execution policies seem to work really well. Although I was not able to dedicate an extensive amount of time, I spent about half an hour trying to circumvent PowerShell’s execution policies. Unfortunately, or fortunately, depending on how you choose to look at it, I had no luck breaking the execution policies. It would seem that a malicious PowerShell script simply cannot run unless an execution policy allows it to do so. So that’s the end of the story, right? Not quite. It took me less than an hour to come up with another method that allowed me to run a malicious PowerShell script.
Before I tell you how I did it, I want to take a step back and answer a question that is fundamental to my approach. Why use PowerShell? Why not just use some other method?
The reason why I wanted to attempt a PowerShell exploit is because PowerShell has really deep integration into the Windows operating system. With a few exceptions, PowerShell can interact with every Windows role, feature, service, and process. PowerShell can access the Windows registry, the Windows Event Log, and pretty much anything else that a malware author might want to tamper with. Furthermore, PowerShell is a part of Windows, which means that a malicious PowerShell script could theoretically attack any modern Windows deployment, including those running on Azure.
As previously mentioned, the execution policy stops malicious PowerShell scripts cold in their tracks, and there doesn’t seem to be an easy way to use an automated script (which the execution policy prevents from running in the first place) to change the execution policy. I’m pretty sure that given enough time, I could probably find a way use a script to change PowerShell’s execution policy, but there is an easier way to make malicious PowerShell code run.
What if the Windows operating system contained a hidden, and completely unprotected, version of PowerShell? And what if there was a way to run a script on this secondary PowerShell environment? Because the secondary PowerShell environment is completely separate from the “normal” PowerShell environment, the execution policies would be completely oblivious to any scripts that you might choose to run.
Now I’m sure that some of you are thinking, “Wait a minute, Posey, that type of environment doesn’t exist. Microsoft would never allow a PowerShell backdoor that circumvents PowerShell’s security.” Well, you would be right. Such an environment does not exist in Windows. You have to download it from Microsoft.
Yes, you read that correctly. Microsoft freely provides an insecure PowerShell environment that can be used to defy PowerShell’s execution policies. It would be logical to assume that you would have to find a way to install this environment onto a victim’s computer before you could run PowerShell malware, but you don’t. The insecure PowerShell environment is completely portable, and can be easily bundled with the malicious script. Do I have your attention yet?
OK, I know that I have made some really outlandish claims, so let me show you just how easy it is to run malicious PowerShell code on a protected system. For this demonstration, I am going to be using Windows 10.
I started my experiment by setting my computer’s execution policy to Restricted, as shown below. This should keep any PowerShell scripts from running on the computer. As you can see in the screencap, I have used the Get-ExecutionPolicy cmdlet to confirm that the execution policy is indeed set to restricted.
OK, so remember that unprotected PowerShell environment that I mentioned? Well, as it turns out, Microsoft doesn’t offer it as a malware authoring tool. Imagine that. Instead, insecure PowerShell environment exists within a utility called PS2EXE.
PS2EXE is a free tool for converting PowerShell scripts into executable files. However, there isn’t really a way to compile a PowerShell script into an EXE file. Since PS2EXE can’t do a true conversion, it encapsulates the PowerShell script into an EXE file, along with a lightweight (and insecure) PowerShell environment. This means that when you run the EXE file, the PowerShell script executes in a completely separate PowerShell environment.
It is worth noting that PS2EXE can’t handle every PowerShell script. This is especially true for scripts that call .NET or that use certain modules. Even so, PS2EXE does allow a PowerShell script to run in spite of a computer’s execution policies.
The first step in the process is to create the PowerShell script that you want to run. For my first attempt, I made a simple script called Payload.ps1. This script simply displays the words “Hello World” and then waits for a key press.
The second step in the process is to use PS2EXE to convert the script into an EXE file. To do that, enter the PS2EXE command, followed by the -Inputfile parameter, the name of your script, and the name of the EXE file that you want to create. You can see how this works below.
Once I created my executable that was based on a “malicious” script, I tried running it. Upon doing so, my antimalware software immediately kicked in and identified the executable as a potential threat, as shown in the screencap below. After a few seconds however, my antimalware software dismissed the threat, and the script was allowed to run.
As you can see in the next screencap below, I ran a PowerShell script on my system in spite of an execution policy forbidding it.
OK, I will be the first to admit that there is a big difference between a “Hello World” script and a virus. Even so, I have illustrated a proof of concept.
I decided to try taking things to the next level, so I modified my Payload.ps1 script so that it would exhibit behavior that was a bit more virus-like. I didn’t want to do anything destructive, but I designed to script to create a file named Evil Trojan, and place the file onto the computer’s hard drive. Here is what the code looks like:
$A = "Insert Malicious Code Here"
$A | Out-File "C:\data\Evil-Trojan.txt"
After modifying my payload file, I re-created my EXE file, and then set the restriction policy back to Restricted. You can see the proof below.
When I ran the EXE file, my antimalware software detected a potential problem, but let the script execute. The “Evil-Trojan” file was created on my hard drive as predicted.
The takeaway: Be prepared
It is a little bit unnerving to think that the PS2EXE utility can be used to circumvent PowerShell security. The best defense against this sort of attack is to use application whitelisting to prevent unauthorized EXE files from running. You can use Windows AppLocker, or any of the third-party utilities.