Protect Against Malware by Enforcing PowerShell Constrained Language Mode
In this Ask the Admin, I’ll show you how to enforce constrained language mode in PowerShell to restrict hackers’ ability to abuse the shell.
The increase in ransomware attacks in the last few months has prompted organizations to review security. One worry is that the ‘power’ in PowerShell might just be a little too prevailing. The truth is that if properly managed and configured, PowerShell and PowerShell Remoting are the most secure ways to manage Windows.
Frameworks, such as PS>Attack and Mimikatz, can exploit PowerShell so that attackers are easily able to compromise users’ credentials. As with any other Microsoft technology, it is recommended to run the latest version of PowerShell to benefit from recent security enhancements, such as script block logging. Starting in PowerShell 5.0, constrained language mode can be enforced to help protect devices from malicious activity. This aids in preventing hackers from loading COM objects, libraries, and classes into PowerShell sessions.
Some of the features of constrained language mode, as described in more detail on Microsoft’s website, including a complete list of allowed types:
- All cmdlets in Windows modules and other UMCI-approved cmdlets are fully functional and have complete access to system resources, except as noted.
- All elements of the Windows PowerShell scripting language are permitted.
- All modules included in Windows can be imported and all commands that the modules export run in the session.
- The Add-Type cmdlet can load signed assemblies but it cannot load arbitrary C# code or Win32 APIs.
- The New-Object cmdlet can be used only on allowed types, which are listed below.
- Only allowed types can be used in Windows PowerShell. Other types are not permitted.
- Type conversion is permitted but only when the result is an allowed type.
Enforcing Constrained Language Mode
There are two ways to enforce constrained language mode in Windows 10: AppLocker and Device Guard User Mode Code Integrity (UMCI). Deploying a Device Guard Code Integrity policy is the preferred way to enforce constrained language mode because Device Guard cannot be easily disabled by users with administrative privilege. And while AppLocker, preferably using script rules in Allow Mode, enforces constrained language mode, an administrator can disable AppLocker by stopping the AppID service. Assuming you practice least privilege in your organization, AppLocker enforcement is better than nothing.
If you want to enforce PowerShell constrained language mode using AppLocker, you do not need to enable all rule types, only script rules. Scripts allowed by AppLocker rules, such as scripts in trusted directories or signed by a trusted code-signing certificate, will run in full language mode. For more information on configuring AppLocker, see Block Untrusted Apps Using AppLocker on the Petri IT Knowledgebase. Additionally, note that blocking PowerShell.exe will not necessarily stop attacks that exploit PowerShell.
The best way to enforce PowerShell constrained language mode is to deploy a Device Guard UMCI policy. For more information on enabling Device Guard in Windows 10, see Enabling Windows 10 Device Guard on Petri. If a Device Guard UMCI policy is applied to a device, a script must be trusted by the policy to run in full language mode.
Bypassing Constrained Language Mode Using PowerShell 2.0
There are features included in Windows 10 for the purposes of backward compatibility. That includes PowerShell 2.0, which is enabled in Windows 10 by default. Keep in mind, it can only be used if version 2.0 of the .NET Framework is also installed. That might occur if the user decides to enable it, as it is there as an optional feature, or if a program gets installed that requires it to be enabled.
If you want to be on the safe side, you can disable PowerShell 2.0 by using the Disable-WindowsOptionalFeature cmdlet from an elevated PowerShell prompt. Alternatively, you can make sure that PowerShell 2.0 is disabled in your gold image from the get-go.
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2
Determine the PowerShell Language Mode
To check the language mode of the PowerShell session, type the following code into a PowerShell prompt:
The above image shows two PowerShell sessions. The first is on a device where AppLocker script rules are enforced in Allowed Mode. The second is on a device where AppLocker is not configured.
In this article, I discussed how to protect against malware that exploits PowerShell by enforcing constrained language mode in PowerShell 5.0.