Bypass PowerShell ConstrainedLanguageMode
Overview
As described in the official Microsoft documentation, the language mode of a PowerShell session determines, in part, which elements of the PowerShell language can be used in the session.
The following four language modes are currently supported in PowerShell:
Language mode | Description |
---|---|
| No restriction imposed and allows all language elements. Default language mode. |
| All commands (cmdlets, functions, etc.) are allowed but the use of script blocks is not permitted. |
| Can only be used through the API as no script text of any form is permitted. |
| All cmdlets and PowerShell language elements are authorized, but it strongly limits the types allowed. For instance, the direct use of .NET methods (such as |
The PowerShell language mode can be defined in the __PSLockdownPolicy
environment variable. The following registry key sets the aforementioned variable system-wide, resulting in the defined language mode to be enforced for all PowerShell sessions:
AppLocker & PowerShell ConstrainedLanguage mode
Starting from PowerShell version 5.0, if a Windows AppLocker
policy in Allow Mode
(whitelisting) is applied to scripts, PowerShell will automatically start in ConstrainedLanguage
mode. As per PowerShell ♥ the Blue Team, this restriction applies to both interactive input and user-authored scripts.
PowerShell language mode retrieval
The following command retrieves the language mode of the current PowerShell session:
Note that in sessions running in RestrictedLanguage
or NoLanguage
mode, the command will return an error, due to the fact that the dot method cannot be used to retrieve property values. The error message returned will however indicate the language mode of the session.
[Unprivileged] ConstrainedLanguage mode bypass using PowerShell downgrade
As the ConstrainedLanguage
language mode was introduced in PowerShell version 3.0, executing PowerShell version 2.0 can be used to easily bypass the restriction:
Note that downgrading PowerShell to circumvent language mode will not be doable on the Windows 10 operating system in a default configuration, as the underlying .NET Framework 2.0
, required to run version 2.0 of PowerShell, is not installed.
[Privileged] System-wide deactivation through removal of the associated registry key
By default, members of the local built-in Administrators
group can modify the __PSLockdownPolicy
registry key, which governs the system-wide setting of the language mode environment variable.
A new PowerShell session must be started after the modification for the new environment variable value to be taken into account.
[Unprivileged] ConstrainedLanguage mode bypass using PowerShell hosts
As the language mode is only applied to powershell.exe
/ PowerShell ISE
, creating a PowerShell host in a C# application may be use to bypass the ConstrainedLanguage
language mode. PowerShell commands can indeed be called in a different runspace in C# application using the System.Management.Automation
library. The PowerShell commands called under this scenario will not be affected by the language mode defined on the system.
Standard binary
The following C# code snipped, adapted from PSByPassCLM
, can be used to emulate an interactive PowerShell console in a runspace unaffected by language mode:
PSByPassCLM
provides an already compiled binary in the project's GitHub repository:
With AppLocker restricting executable usage
If Windows AppLocker
is enabled, and a policy restrict the execution of binaries, AppLocker
will have to be circumvented in order to bypass the PowerShell ConstrainedLanguage
language mode. In its default configuration, AppLocker
can be easily bypassed. Refer to the Windows - Bypass AppLocker
note for more information on how to enumerate the defined rules and default-configuration bypass techniques.
If an hardened AppLocker
configuration is implemented, the following tools leverage Windows built-in binaries, that may be allowed by the AppLocker
rules defined in the targeted environment, to bypass the ConstrainedLanguage
language mode. Windows built-in binaries are exploited to load a C# Dynamic Link Library (DLL)
that uses the System.Management.Automation
library to emulate an interactive PowerShell console unaffected by language mode (similarly to what is accomplished by the script above).
Tool | Exploited built-in binaries | Command |
---|---|---|
|
| x86 systems:
|
|
|
|
|
| Generation of the |
References
http://www.3nc0d3r.com/2016/12/pslockdownpolicy-and-ways-around-it.html https://github.com/p3nt4/PowerShdll https://s3cur3th1ssh1t.github.io/Playing-with-OffensiveNim/ https://decoder.cloud/2017/11/17/we-dont-need-powershell-exe-part-3/ https://github.com/padovah4ck/PSByPassCLM https://www.sysadmins.lv/blog-en/powershell-50-and-applocker-when-security-doesnt-mean-security.aspx https://github.com/stonepresto/CLMBypass
Last updated