Thinking about your Powershell execution policy
The majority of security incidents normally happen because of configurations made with the quick and easy approach. It solves a constraint in that very moment but it never gets reviewed again.
It's the Lazy Admin Rule: In every organisation there's at least a process that follows insecure steps just for the sake of convenience.
Because Powershell is a native system tool, it's one of the go-tos when targeting lateral movement after compromising at least one VM. This could be achieved using script execution via social engineering, or after compromising one of the vulnerable internal systems.
Powershell execution policy was originally designed to prevent and admin running a potentially malicious script of unknown origin by accident. However, there's still a lot to do in that aspect and admins see it as hard work. It's still a valid initial control for users who download random scripts and run it on the network without checking it
There are methods to bypass PowerShell execution policies, but we want to make things a bit more difficult for an attacker. That would require a bit more knowledge from a potential bad actor, lowering the risk just a notch. Most malicious attackers are script kiddies or expect someone on the inside to run their scripts. Execution policies are not a Security Control after all and users can change easily it, but it helps when the technology team keeps growing.
When execution policy is set to restricted, Powershell will display the following error when executing a script.
File cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ CategoryInfo : SecurityError: (:) , PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
That means that the result will return Restricted when running the command
Before changing the policy as Bypass because it is convenient, examining and deciding the best solution will save time in the future. It doesn't matter if it is on your personal machine, a Windows Server Machine or GPO.
The presented options are:
- Restricted: You're here right now. This policy won't allow any scripts to run. To be set to use Powershell just to run commands from console.
- AllSigned: Will only run scripts to run from a trusted publisher.
- RemoteSigned: Downloaded or unknown scripts must be signed before being able to be executed.
- Undefined: Ignores the current system execution policy unless it is enforced via Group Policy.
- Unrestricted: All scripts can run but will be verbose.
- Default: Uses the default policy defined by Microsoft. Restricted on desktops, RemoteSigned on servers.
- Bypass: Ignores restrictions and executes scripts without verbosity.
The scope: The command Get-ExecutionPolicy -List will define what's covered by the policy. It depends a lot on the use case, but to administer a large number of machines, MachinePolicy would go the goto.
Don't forget that remote or local execution is an element to consider when engineering the scope.
Abou trusted publishers and signing scripts
This is probably one of the most confusing concepts around Powershell execution: What is a trusted publisher?
It's all down to digitally sign scripts using a certificate. A Trusted Publisher in the Windows world is an identity with a certificate stored in the Trusted Publishers Certificate Store. There isn't a concrete list of providers, will be the sort that administers driver packages, trusted applications, system tools, etc.
On a custom script, a self-signed certificate can be generated by the Certificate Creation Tool, add it as a trusted certificate and reference the script if it is to be run within an organisation. An externally signed Powershell script will have a signature block followed by a very low string of alphanumeric characters, generally at the bottom.
If an unsigned script is run, the return error would look like this:
The file cannot be loaded. The file is not digitally signed. The script will not execute on the system. Please see "Get-Help about_Signing" for more details.
Of course, the restriction can be bypassed on unique cases by running the command Unblock-File. Please, this is to be avoided if the script is of unknown origin or functionality.
Enforcing execution policies
Here's were Group Policies come to play. It is advisable to target Powershell Security Policies on a group of machines rather than a group of users, the policy could be easily bypassed using another user on the same machine or with elevation of privileges.
It is always recommendable rolling out the policy on a machine test pool and wait at least 24 hours.
To enforce execution policies across multiple machines on a domain, there's a template named Turn on Script Execution on most versions of Group Policy Management Editor.
The key thing is to engineer the scope of the policy appropriately, as it could restrict or delay people's works. That's why feedback and a test pool of active users are important.
If for some reason there is a need to enforce execution policies on machines or users not attached to Active Directory, or without using Group Policies, there's plenty of alternatives that require a bit of more work but can be reused on the long run. A simple script configured in the standard image that runs on boot-up would do the trick.
To conclude, standardising execution policies takes a bit of planning at the beginning but sets a framework for adequate Infrastructure security, helps to avoid future incidents and adds an additional filter.