One will see in many places in Microsoft documentation and in several books out there that PowerShell has security system called Execution Policy, I personally do not agree this is a security measure but just a simple control to protect from accidental execution of code not specifically allowed thru normal means. First lets cover what are the security minded default configurations that PowerShell has:

It does not execute scripts by double clicking on them by default.

All scripts must be digitally signed with a trusted digital certificate by the host system so as to be able to execute.

All script when executed in a PowerShell session must be executed by providing the path of the script wither relative or full they cannot be executed just by name.

Code is executed under the context of the user.

Code that is downloaded via a web browser or thru emails clients that mark the file as downloaded from the Internet in the file meta-data the file will blocked from execution unless specifically allowed.

Control of Execution - Control the level of trust for executing scripts.

- Control the level of trust for executing scripts. Command Highjack - Prevent injection of commands in my path.

- Prevent injection of commands in my path. Identity - Is the script created and signed by a developer I trust and/or a signed with a certificate from a Certificate Authority I trust.

Is the script created and signed by a developer I trust and/or a signed with a certificate from a Certificate Authority I trust. Integrity - Scripts cannot be modified by malware or malicious user.

Copy pasting the content of the script in to PowerShell.

Encoding the script in Base64 and running it from the command line as an argument to the powershell.exe

Enter each command by hand and execute it.

Changing Execution Policy

Restricted No Script either local, remote or downloaded can be executed on the system.

No Script either local, remote or downloaded can be executed on the system. AllSigned All script that are ran require to be digitally signed.

All script that are ran require to be digitally signed. RemoteSigned All remote scripts (UNC) or downloaded need to be signed.

All remote scripts (UNC) or downloaded need to be signed. Unrestricted No signature for any type of script is required.

MachinePolicy : The execution policy set by a Group Policy for all users.

: The execution policy set by a Group Policy for all users. UserPolicy : The execution policy set by a Group Policy for the current user.

: The execution policy set by a Group Policy for the current user. Process : The execution policy that is set for the current Windows PowerShell process.

: The execution policy that is set for the current Windows PowerShell process. CurrentUser : The execution policy that is set for the current user.

: The execution policy that is set for the current user. LocalMachine: The execution policy that is set for all users.

C:\Windows\system32> Get-ExecutionPolicy -List | ft -AutoSize Scope ExecutionPolicy

----- ---------------

MachinePolicy Undefined

UserPolicy Undefined

Process Undefined

CurrentUser Undefined

LocalMachine RemoteSigned

These defaults settings provide the following protections:Microsoft took great care and attention to minimize the attack surface of PowerShell when an attacker tries to trick a user in to executing a possibly malicious script. Once on the system things change since these controls cannot protect from:Sadly PowerShell does not provide a way to block specific cmdlets or .NET APIs from users to do a more fine grained control on system. This allows say malware already present on the system or an attacker that has been able to get a foothold on the system to leverage PowerShell. An example of this is the first known use of Powershell Code as Malware in the wild http://nakedsecurity.sophos.com/2013/03/05/russian-ransomware-windows-powershell/ in addition to this PowerShell has also been added to what I call dual purpose tools like Metasploit and Social Engineering Toolkit that are written primarily for Penetration testers and researchers but sadly can also be used by a malicious attacker does why I refer to them as dual purpose tools.To control the validation of scripts and cmdlets that be use thecmdlet is used. There are several Policies that can be used:Each of these policies can be applied to different scopes to control who is affected by them, the scopes are:The default scope is LocalMachine and it will apply to everyone on the machine when set via PowerShell it self. To get the current execution policy we use thecmdlet running it in a session as administrator and we give it theparameter to list all scopes

Typically for admin workstations I recommend RemoteSigned since any code downloaded from the internet I will not execute it by accident causing harm to my machine. Lets change it from RemoteSigned to Restricted, for this we use the Set-Executionpolicy and give it the policy name, we can use the –Force parameter so it will not ask for confirmation and we can conform by traying to execute a script:

C:\Windows\system32> Set-ExecutionPolicy Restricted -Force

C:\Windows\system32> C:\Users\Carlos\Desktop\hello.ps1

C:\Users\Carlos\Desktop\hello.ps1 : File C:\Users\Carlos\Desktop\hello.ps1 cannot be loaded because running scripts is

disabled on this system. For more information, see about_Execution_Policies at

http://go.microsoft.com/fwlink/?LinkID=135170.

At line:1 char:1

+ C:\Users\Carlos\Desktop\hello.ps1

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : SecurityError: (:) [], PSSecurityException

+ FullyQualifiedErrorId : UnauthorizedAccess

Code Signing

Code signing allows us to use cryptographic signatures to gain the following capabilities:



Provides an identity of the source of code.

Ensure detection of script modification.



To be able to add a digital signature to a script we must use a Authenticode Digital Certificate, the certificate can come from:



Certificate from a Certificate Authority - This type of certificate allows the signing and sharing of scripts. If a Commercial CA is used the script could be shared outside of an organization.

- This type of certificate allows the signing and sharing of scripts. If a Commercial CA is used the script could be shared outside of an organization. Self-Signed Certificate - This certificate is generated by a CA hosted in he computer it self where it is used.



Self-Signed Certificates

Lets look at generating a self signed certificate for use in code signing. We start by using the makecert.exe tool from the Windows SDK that can be downloaded from Microsoft for free.



Run a Windows Command Prompt as Administrator





Run the following command in the Command Prompt. It creates a local certificate authority for your computer:





makecert -n "CN=PowerShell Local Certificate Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine



When prompted for a Private Key password provide one of your choosing that you are able to remember and confirm the password.

When prompted again for the password enter the password you entered in the previous step.



Next we need to use MMC for opening the local certificate store and saving the certificate:



Open Windows MMC on Windows





In the console window click on File and select Add/Remove Snap-in





Select “Certificates” and click on “Add”





When prompted accept the default of “My user account” and click on “Finish”





Click on OK. This will give you a Management Console for your current user Certificate Store so we can look at the results from the commands and manage the certificates from the Windows GUI with ease.





Go in to the MMC Console and Select “Trusted Root Certification Authorities” -> “Certificates” and on the right pane ensure there is a Root Certificate for “PowerShell Local Certificate Root”

and on the right pane ensure there is a Root Certificate for Run the following from a Command Prompt, give in the Common name filed a friendly name including your username/handle. It generates a personal certificate from the above certificate authority:





makecert -pe -n "CN=Carlos PowerShell CSC" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer



You will be prompted for the certificate Private Key Password, enter the password that you provided when creating the CA Private Key.

To verify that the certificate was created and stored in the proper location go in to the console MMC Console and Select “Personal” -> “Certificates” and on the right pane ensure there is a certificate with the name that you specified in the command to create the signing certificate



You are now ready to use the self signed certificate.

Exporting Self-Signed Certificate

If you want you can export the self signed certificate for use in other systems, for that follow these steps:



Expand “ Personal ”, right click on the appropriate code signing certificate and select “All Tasks” -> “Export…”.

”, right click on the appropriate code signing certificate and select Choose the option “Yes, export the private key” when prompted.

when prompted. Accept the default options on the “Export File Format” screen.

screen. Enter a password for the private key, which will need to be entered when importing the certificate

Save the certificate to an appropriate location.

Right click “Trusted Publishers” and select “All Tasks” -> “Import…”

and select Follow the wizard to import the exported certificate, and enter in the accompanying password that was used when the certificate was exported.

Accept all the default values for the remaining steps in the wizard.

If the certificate is no longer required to be imported by other machines, it is highly recommended that the exported file is deleted.

Verify that the certificate was properly installed under the correct location



Signing Certificates via Active Directory Certificate Services



From Administration Tools select the Certificate Authority Console on your Enterprise Root Certificate Authority

select the on your Right click on Certificate Templates and select Manage





Double click on the Code Signing template to open it’s Properties





Add the group that you want to be able to request code signing certificates

Allow Read and Enroll





Right Click on Certificate Templates -> New -> Certificate Template to Issue





Click on the Code Signing template

template Click on OK and close the Certificate Authority Console



On the developers machine:



Open a new MMC console

From the File Menu select Add/Remove Snap-in





Select Certificates , click on Add and click on Ok

, click on and click on Make sure that My user account is selected





Click on Finish

Click on Ok





Right click on Personal Select All Tasks -> Request New Certificate





Click Next on the screen that appears

on the screen that appears Select Active Directory Enrollment Policy and click on Next

and click on Select the Code Signing certificate template

certificate template Expand Details and click on Properties





Select the Private Key

Select Make private key exportable

Click on Ok





Click on Enroll

Click on Finish



Using the Code Signing Certificate

Since the certificate store is mapped as a PSDrive automatically we can check if a code signing certificate is available directly from PowerShell. Having PowerShell have access to the certificate store allows to very easy manipulation and signing scripts and other files, the cmdlets for working with Authenticode are:



Get-AuthenticodeSignature checks the Authenticode signatures for files that support Subject Interface Package (EXE, PS1, PSXML, DLL, VBS ..etc.

checks the Authenticode signatures for files that support Subject Interface Package (EXE, PS1, PSXML, DLL, VBS ..etc. Set-AuthenticodeSignature adds an Authenticode signature for files that support Subject Interface Package



In fact the cmdlets as we can see not only allow us to sign PowerShell Scripts and Modules but we can also sing several windows files.

To list the certificates we can just use the certificate store like any drive and ask to only show code signing certificates using the –CodeSigningCert parameter when Certificate Store PSDrive is used





For signin the certificate must be passed as a object to the Set-AuthenticodeSignature cmdlet so we may need to save it in to a variable. Signing of a script would be like this:

PS C:\> $acert = ( dir Cert:\CurrentUser\My -CodeSigningCert )[ 0 ] PS C:\> Set-AuthenticodeSignature .\hello.ps1 -Certificate $acert

Now when we check our script we will see it is signed:

PS C:\> Get-AuthenticodeSignature .\hello.ps1 | ft -AutoSize Directory: C:\Users\Carlos Perez\Desktop SignerCertificate Status Path ----------------- ------ ---- 9854ABA48101875C7D9A7F79F8DD0B71C911F73C Valid hello.ps1

The script should now look like this:

So I hope you liked the blog post and found it informative on the second part I will cover how to bypass the execution policy and how an attacker or malware may abuse it.