Today we will cover PowerShell Language Modes in this Article.
In this article, we will discuss the different language modes of PowerShell. In Part 1, we’ll look at all the basics around PowerShell and its different types. In Part 2, we’ll look at some of the workarounds that were discovered in previous versions of Windows.
What is a language mode and its types?
A language mode is a core feature in PowerShell that defines what all elements can be used in a PowerShell session. So the language mode is a property of the session configuration that is used to create the session. Remote sessions are established using the remote computer’s session configuration. Below are the different types of PowerShell language mode:
PowerShell Language Modes:
Full language: In this mode, users can use all elements of a PowerShell session and is the default mode except for Windows RT. Below is how we see the default language mode
Limited Language: As the name suggests, there are some restrictions in this language mode. This mode is useful for performing routine administrative tasks and yet limits the language elements that can be used to invoke arbitrary APIs. We will talk about this language mode in the sections below. Below is how the default language mode can be changed and we can see that the methods cannot be called in the restricted language mode. Only those methods that have been exclusively exported from the module can be called in this method. This will be discussed in more detail in the next section.
Restricted Language: In this mode, users can run routines, workflows, and functions, but cannot run script blocks. Below we can see that the language mode has changed from Full to Limited. After the change, it is not possible to execute the same command again because it cannot refer to properties in restricted language modes
Only the following variables and operators are allowed in this mode.
- -eq (equal to)
- -gt (greater than)
- -lt (less than)
We see it below
- No Language: In this mode, the user can run the command but will not use ANY language elements. Commands that are part of System.Management. Automation.Runspaces are only allowed. Below we can see that the language mode has changed from Full to NoLanguage and after the change it doesn’t even support the same command because the syntax is not supported either.
- The Environment Variable__PSLockdownPolicy also controls all of these language modes in the HKLMSYSTEMCurrentControlSetControlSession ManagerEnvironment and is often used by Group Policy for cross-domain enforcement. MS officially documents this variable, so its values are correctly defined. Below we see how the __PSLockdownPolicy setting affects the language mode.
- A value of 0 indicates FullLanguage Mode
- A value of 4 Indicates ConstrainedLanguage mode
- Because these language modes, if used correctly, can effectively prevent any malicious code from running (if we believe that the settings cannot be bypassed), but setting these settings without properly evaluating existing scripts that are executed remotely and depend on elements such as block scripts may result in the execution of these scripts being interrupted.
- Now that we are clear about the basics of language modes, let’s dive deeper into one of the important language modes, ConstrainedLanguage Mode. This mode was designed to work with the User Mode Code Integrity (UMCI) system policy.
What are UMCI policies?
The Code Integrity Policy is part of a whitelisting solution that was introduced in Windows 10/2016 to block WSScript-VBS, js, wsf, PowerShell, drivers, and user-mode binaries that are not explicitly allowed by this policy. This solution is known as Device Guard. So code integrity is part of Device Guard that enforces both kernel mode code integrity (KMCI) and user mode code integrity (UMCI).
So scripts that are not listed as part of UMCI will be forced to run in ConstrainedLanguage mode. This can prevent any unsigned code from running, for example when put into restricted language mode, the ability to call Add-Type is restricted, which can prevent arbitrary types from being created. Other important restrictions enforced by the restricted language mode are listed below:
As we saw above in the screenshot, functions must be explicitly exposed by the module, otherwise they cannot be used. Also, functions must be explicitly declared on exposure, and wildcards are not supported.
Only whitelisted specific .NET types are allowed, which helps limit the invocation of arbitrary Win32 APIs.
Start-Job is not available if the system is not protected by the policy because it starts a new process in full language mode. If the policy is enforced, it will always run in restricted language mode.
XAML-based workflows are blocked in ConstrainedLangugae mode. Why will we see this in part 2?
Commands and even supported commands are not allowed in the DATA section.
So above are some limitations imposed by the limited mode. In the next part of this article, we will look at various techniques that have been discovered in the past to bypass the forced language mode.