What is PowerShell?
PowerShell is a scripting framework and command shell, built on .NET. It is implemented, by default, on Windows Operating Systems (OSs). It is object-based, which means that everything you work with (such as variables, input, and more) has properties and methods. That opens up a lot of possibilities when working with PowerShell.
Additionally, PowerShell has a pipeline and allows you to pipe input into other commands to reuse it. This combines the advantages of a command line-based script language with an object-oriented language. And on top of this, it has a built-in help system that allows you to help yourself while working on the console.
PowerShell does not exclusively run on Windows OSs. Since PowerShell Core was released in 2016, it can run on any OS, including Linux and macOS devices.
It helps security professionals to get a lot of work done in a very short space of time. Not only do blue teamers find it useful, but also red teamers. As with every feature that provides a lot of capabilities and enables you to do your daily work in a more efficient way, it can be used for good and bad purposes. It can be a mighty tool for professionals, but as usual, security professionals need to do their part to secure their environments so that existing tools and machines will not be abused by adversaries.
But first, let's take a look at how PowerShell was born and how it developed over the years.
The history of PowerShell
Before PowerShell was created, there were already Command Line Interfaces (CLIs) available, shipped with each OS to manage the system via command line: COMMAND.COM
was the default in MS DOS and Windows 9.x, while cmd.exe
was the default in the Windows NT family. The latter, cmd.exe
, is still integrated within modern Windows OSs such as Windows 10.
Those CLIs could be used to not only execute commands from the command line but also to write scripts to automate tasks, using the batch file syntax.
Because not all functions of the Graphical User Interface (GUI) were available, it was not possible to automate all tasks via the command line. Additionally, the language had inconsistencies, so scripting was not as easy as it should have been in the first place.
In 1998, Microsoft released Windows Script Host (cscript.exe
) in Windows 98 to overcome the limits of the former CLIs and to improve the scripting experience. With cscript.exe
, it now became possible to work with the APIs of the Component Object Model (COM), which made this interface very mighty; so mighty that not only did system administrators leverage this new feature but also the malware authors. This quickly lent cscript.exe
the reputation of being a vulnerable vector of the OS.
Additionally, the documentation of Windows Script Host was not easily accessible, and there were even more CLIs developed for different use cases besides cscript.exe
, such as netsh
and wmic
.
In 1999, Jeffrey Snover, who had a UNIX background, started to work for Microsoft. Snover was a big fan of command lines and automation, so his initial goal was to use UNIX tools on Microsoft systems, supporting the Microsoft Windows Services for UNIX (SFU).
However, as there is a big architectural difference between Windows and UNIX-based systems, he quickly noticed that making UNIX tools work on Windows didn't bring any value to Windows-based systems.
While UNIX systems relied on ASCII files that could be easily leveraged and manipulated with tools such as awk
, sed
, grep
, and more, Windows systems were API-based, leveraging structured data.
So, he decided that he could do better and, in 2002, started to work on a new command-line interface called Monad (also known as Microsoft Shell/MSH).
Now, Monad not only had the option to pass structured data (objects) into the pipe, instead of simple text, but also run scripts remotely on multiple devices. Additionally, it was easier for administrators to use Monad for administration as many default tasks were simplified within this framework.
On April 25, 2006, Microsoft announced that Monad was renamed PowerShell. In the same year, the first version of PowerShell was released, and not much later (in January 2007), PowerShell was released for Windows Vista.
In 2009, PowerShell 2.0 was released as a component of Windows 7 and Windows Server 2008 R2 that was integrated, by default, into the OS.
Over the years, PowerShell was developed even further, and many new versions were released in the meantime, containing new features and improvements.
Then, in 2016, Microsoft announced that PowerShell would be made open source (MIT license) and would also be supported cross-platform.
PowerShell 5.1, which was also released in 2016, was the last Windows-only PowerShell version. It is still shipped on Windows systems but is no longer developed.
The PowerShell team was in the process of supporting Nano Server. So, there was a full version of PowerShell supporting Windows servers and clients. Nano Server had a severely trimmed version of .NET (called .NET Core), so the team had to reduce functions and chop it down to make PowerShell work with .NET Core. So, technically PowerShell 5.1 for Nano Server was the first version of PowerShell Core.
The first real and official version of PowerShell Core was 6.0, which also offered support for cross-platform such as macOS and Linux.
Why is PowerShell useful for cybersecurity?
PowerShell runs on most modern Windows systems as a default. It helps administrators to automate their daily workflows. Since PowerShell is available on all systems, it also makes it easier for attackers to use the scripting language for their own purposes – if attackers get access to a system, for example, through a credential theft attack.
For attackers, that sounds amazing: a preinstalled scripting framework that provides direct access to cmdlets and the underlying .NET Framework. Automation allows you to get a lot done – not just for a good purpose.
Is PowerShell dangerous, and should it be disabled?
No! I have often heard this question when talking to CISOs. As PowerShell is seen more and more in the hands of the red team, some people fear the capabilities of this mighty scripting framework.
But as usual, it's not black and white, and organizations should rather think about how to harden their systems and protect their identities, how to implement better detection, and how to leverage PowerShell in a way that benefits their workloads and processes – instead of worrying about PowerShell.
In the end, when you set up a server, you don't just install it and connect it to the internet. The same goes for PowerShell: you don't just enable PowerShell remote usage in your organization allowing everybody to connect remotely to your servers, regardless of their role.
PowerShell is just a scripting language, similar to the preinstalled cscript or batch. Technically, it provides the same potential impact as Java or .NET.
And if we compare it to Linux or macOS, saying that PowerShell is dangerous is like saying that Bash or zsh is dangerous.
A friend who worked in incident response for many years once told me about adversaries dropping C# code files on the target boxes and calling csc.exe (which is part of the .NET Framework) to compile the dropped files directly on the box. Which is a very effective way to abuse a preinstalled software to install the adversary's code on the system without even leveraging PowerShell.
So, in other words, it is not the language that is dangerous or malicious; adversaries still require identities or authorization for the execution, which can be constrained by the security expert or administrator who is responsible for the environment's security.
And to be honest, all red teamers that I know or have talked to are starting to move more and more to other languages such as C# or C++ instead of PowerShell, if they want to stay undetected during their attacks.
If the right security measures and detections are implemented, it is almost impossible to go unnoticed when using PowerShell for an attack in a well-configured and protected environment. Once you have followed the security best practices, PowerShell will support you to keep your environment safe and help you track any attackers in your environment.
Additionally, a lot of your environmental security depends on your global credentials and access hygiene: before attackers can leverage PowerShell, first, they need access to a system. We'll take a closer look at how to secure your environment credential-wise in Chapter 6, Active Directory – Attacks and Mitigation.
How can PowerShell support my blue team?
PowerShell not only enables your IT professionals to work more efficiently and to get things done quicker, but it also provides your security team with great options.
PowerShell offers a lot of built-in safety guards that you will learn more about in this book:
- Automation and compliance: One of the main benefits is that you can automate repeatable, tedious tasks. Not only will your administrators benefit from automating tasks, but your Security Operations Center (SOC) can automate response actions taken, triggered by certain events.
One of the main reasons organizations are getting breached is missing security updates. It is not easy to keep all systems up to date – even with updated management systems such as Windows Server Update Services (WSUS) in place. PowerShell can help to build a mechanism to regularly check whether updates are missing to keep your environment secure.
Auditing and enforcing compliance can easily be achieved using Desired State Configuration (DSC).
Automate security checks to audit Active Directory or server security and enforce your security baselines. DSC allows you to control the configuration of your servers at any time. You can configure your machines to reset their configuration up to every 15 minutes to the configuration you specified.
Additionally, if you integrate DSC as part of your incident response plan, it is very easy to rebuild potentially compromised servers from the scratch.
- Control who is allowed to do what and where: By configuring PowerShell remoting/WinRM, you can specify who is allowed to log on to which device or server. Of course, it does not help against credential theft (as this is not a PowerShell topic), but it helps to granularly define which identity is allowed to do what. Additionally, it provides great auditing capabilities for remote connections.
Constrained Language mode lets you restrict which PowerShell elements are allowed in a session. This can already help to prevent certain attacks.
And using Just Enough Administration (JEA), you can even restrict which roles/identities are allowed to run which commands on which machine. You can even restrict the parameters of a command.
- Find out what is going on in your environment: PowerShell provides an extensive logging framework with many additional logging options such as creating transcripts and script block logging.
Every action in PowerShell can be tracked if the right infrastructure is put behind it. You can even automate your response actions using a Security Orchestration, Automation, and Response (SOAR) approach.
Using PowerShell, you can quickly pull and search event logs of multiple servers, connecting remotely to analyze them.
In a case of a security breach, PowerShell can also help you to collect and investigate the forensic artifacts and to automate the investigation. There are great modules such as PowerForensics that you can reuse for your forensics operations and post-breach remediation.
- Restrict which scripts are allowed to run: By default, PowerShell brings a feature called Execution Policy. Although it is not a security control, it prevents users from unintentionally running scripts.
Signing your code helps you to verify whether a script that is run is considered legit: if you allow only signed scripts to run, this is a great way to prevent your users to run scripts directly downloaded from the internet.
AppLocker, in combination with Code Signing, can help you to control which scripts are allowed to run in your organization.
The mentioned solutions do not restrict interactive code restriction though.
- Detect and stop malicious code from execution: The Antimalware Scan Interface (AMSI) provides a possibility to have your code checked by the antimalware solution that is currently present on the machine. This can help to detect malicious code and is also a great safeguard against file-less malware attacks (living off the land) – attacks that don't require files to be stored on the machine, but rather directly run the code in memory.
It is integrated directly into PowerShell and can assess scripts, interactive use, and dynamic code evaluation.
These are only some examples of how PowerShell can support the blue team, but it should already give you an overview of how blue teamers can benefit from using and auditing PowerShell.
It is also worth reading the great blog article PowerShell ♥ the Blue Team that the Microsoft PowerShell team has published to provide advice on how PowerShell supports blue teamers: https://devblogs.microsoft.com/powershell/powershell-the-blue-team/.
You will learn more about possible attacks, mitigations, and bypasses during your journey throughout this book.
But first, let's start refreshing your knowledge of PowerShell fundamentals. Enjoy!