Windows PowerShell 1.0 Security

Revision as of 18:36, 30 December 2008 by Neil (Talk | contribs) (Signing a Windows PowerShell Script)

Revision as of 18:36, 30 December 2008 by Neil (Talk | contribs) (Signing a Windows PowerShell Script)

The objective of this chapter of Windows PowerShell 1.0 Essentials is to provide an overview of the security mechanisms provided with Windows PowerShell, including configuration of script execution policies and the signing of PowerShell scripts through the use of digital certificates.

Windows PowerShell Script Execution Policy

By default, the execution of scripts in the Windows PowerShell environment is disabled (although it is still possible to execute commands interactively at the PowerShell command prompt). This is controlled by the Windows PowerShell script execution policy setting. Attempting to run a script when in this restricted mode will result in the following error being displayed:

PS C:\Users\Administrator> ./t.ps1
File C:\Users\Administrator\t.ps1 cannot be loaded because the execution of scripts is disabled on
this system. Please see "get-help about_signing" for more details.
At line:1 char:7
+ ./t.ps1 <<<<

In addition to restricted mode, AllSigned, RemoteSigned and Unrestricted modes are also available, details of which are outlined in the following table:

Execution Policy

Description

RestrictedThe default policy on Windows PowerShell, this mode disables the execution of script files. Windows PowerShell may only be used by manually issuing commands at the command prompt.
AllSignedLimits execution to scripts which are authenticode signed. When a signed script is executed, PowerShell will prompt for confirmation that the signer of the script can be trusted.
RemoteSignedRequires that any scripts that have been downloaded from a remote location must be signed before they may are permitted to execute.
UnrestrictedAllows any script to be executed, regardless of origin or whether it is signed.

In general, use of the Unrestricted execution policy is not recommended. For most practical purposes, RemoteSigned mode is the recommended choice as it allows locally created scripts to execute but imposes a level of security for scripts downloaded from remote locations.

Identifying and Changing the Current Execution Policy

The current execution policy may be identified using the Get-ExecutionPolicy cmdlet:

PS C:\Users\Administrator> get-executionpolicy
Restricted

In order to change the prevailing execution policy, the Set-ExecutionPolicy cmdlet is used in conjunction with the new execution policy setting. For example, to change to RemoteSigned, the following command should be executed:

PS C:\Users\Administrator> set-executionpolicy remotesigned

Signing Windows PowerShell Scripts

The signing of Windows PowerShell scripts serves two key purposes. The first, through the use of a digital certificate, is to provide a level of confidence that a script has been provided by a trusted author. Secondly, through the use of public key cryptography and one-way hashing, the signing process also ensures that any modifications made to a script after it was signed by the author are detected and execution of the script subsequently blocked.

Windows PowerShell scripts are signed using a digital certificate which is obtained from a certificate authority (CA). Alternatively, a self-signed certificate may be generated by creating a local certificate authority. Whilst these self-signed certificates are useful for running scripts on a local system, they are not trusted by other systems. The certificate may be further protected by using private key encryption. More details on certificates and Public Key Infrastructure may be found in the Techotopia Security+ Essentials online book in the chapter entitled An Overview of Public Key Infrastructures (PKI).

In the remainder of this chapter, we will create a local certificate authority, generate a signing certificate and apply that certificate to a script. Having done that, we will then enable private key encryption on that certificate to prevent it from falling into the wrong hands. If you already have a certificate issued by a certificate authority you may, of course, skip the self-signing sections of this chapter and proceed to the script signing section.

Setting up a Local Certificate Authority

A local certificate authority is created using the makecert.exe tool which is available as part of the Windows Platform SDK which may, in turn, be downloaded from the Microsoft web site. The exact location of the makecert.exe executable will vary between Windows platforms and versions. Often the best way to locate the file after the SDK has been installed is to perform a search of the local system. Once the location has been identified, add it to the Windows PATH environment variable.

To create a local certificate authority, issue the following command at the Windows PowerShell prompt:

PS C:\Users\Administrator> makecert -n "CN=PowerShell Certification Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 
-r -sv cert.pvk cert.vcer -ss Root -sr localMachine

When executed, a dialog box will appear as illustrated in the following figure prompting for a Private Key Password. Enter a suitable password and click on the OK button to proceed.

Specifying a private key password for a self signing authority

If the creation process is successful, the makecert.exe tool will display Succeeded before returning to the prompt.

Creating a Certificate

A self-signed certificate is created using the makecert.exe tool once again as illustrated below:

PS C:\Users\Administrator> makecert -pe -n "CN=PowerShell Cert" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv cert.pvk -ic cert.cer
Succeeded

Before generating the certificate, a dialog will appear requesting the password specified in the preceding section. Enter the password and click OK to continue.

On completion, the certificate will be located in the specified file, cert.cer in the above example. In addition the private key is contained in the cert.pvk file. The certificate will also be placed into the system's certificate store, and may be viewed and accessed by issuing the following command:

PS C:\Users\Administrator> get-childitem cert:\currentuser\my -codesign | fl

Subject      : CN=PowerShell Cert
Issuer       : CN=PowerShell Certification Root
Thumbprint   : 3152D8D9584375916BB9A7511BF2E789F257AD0B
FriendlyName :
NotBefore    : 12/30/2008 8:31:38 AM
NotAfter     : 12/31/2039 3:59:59 PM
Extensions   : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

As shown in the above output, the certificate creation process specified default start and end dates for period of validity. Different dates may be specified during creation through the use of the -b and -e options:

PS C:\Users\Administrator> makecert -pe -n "CN=PowerShell Cert" -b 01/01/2009 -e 01/01/2020 -ss MY -a sha1 
-eku 1.3.6.1.5.5.7.3.3 -iv cert.pvk -ic cert.cer
Succeeded

Signing a Windows PowerShell Script

The first step in signing a PowerShell script is to obtain the certificate and assign it to a variable:

PS C:\Users\Administrator> $certificate = @(get-childitem cert:\currentuser\my -codesigning)[0]

The [0] index in the above command instructs PowerShell to use the first certificate in the store. If multiple certificates are stored, the index value should be modified to match the desired certificate. For example, to access the second certificate the index would need to be changed to [1].

Having extracted the certificate object from the store, the next step is to configure PowerShell to only accept signed scripts:

PS C:\Users\Administrator> set-executionpolicy allsigned

At this point, any attempt to execute an unsigned script will result in an error message:

PS C:\Users\Administrator> ./t.ps1
File C:\Users\Administrator\t.ps1 cannot be loaded. The file C:\Users\Administrator\t.ps1 is not 
digitally signed. The script will not execute on the system. Please see "get-help about_signing" for
more details..
At line:1 char:7
+ ./t.ps1 <<<<

The next step is to sign the script, a task which is achieved using the Set-AuthenticodeSignature cmdlet passing through the script name and certificate as arguments:

PS C:\Users\Administrator> set-authenticodesignature ./t.ps1 $certificate


    Directory: C:\Users\Administrator


SignerCertificate                         Status                       Path
-----------------                         ------                       ----
3152D8D9584375916BB9A7511BF2E789F257AD0B  Valid                        t.ps1

Attempting to execute the script now causes PowerShell to display a warning that the script was signed by an untrusted publisher, but provides the option to run the script anyway (Run once), or to run the script and also trust all future scripts signed with this certificate (Always run):

PS C:\Users\Administrator> ./t.ps1

Do you want to run software from this untrusted publisher?
File C:\Users\Administrator\t.ps1 is published by CN=PowerShell Cert and is not trusted on your
system. Only run scripts from trusted publishers.
[V] Never run  [D] Do not run  [R] Run once  [A] Always run  [?] Help (default is "D"):

Previously in this chapter, it was noted that signing also prevents tampering with the contents of a script. When the contents of a signed script are modified, an attempt to execute the script will result in the following error:

PS C:\Users\Administrator> ./t.ps1
File C:\Users\Administrator\hello.ps1 cannot be loaded. The contents of file C:\Users\Administrator
\hello.ps1 may have been tampered because the hash of the file does not match the hash stored in the 
digital signature. The script will not execute on the system. Please see "get-help about_signing"
 for more details..
At line:1 char:11
+ ./hello.ps1 <<<<

Protecting Certificates with Private Key Encryption

In the above examples, we were able to extract a certificate from the system's certificate store and sign PowerShell scripts without having to prove who we are. The danger in this is that anyone with access to the certificate could use to to sign any script, including a malicious script which would then potentially be trusted by other users. Clearly, an additional layer of defense is desirable, and this is provided through private key encryption of the certificate.

Installed along with the makecert.exe tool was another tool known as the Certificate Manager which is used, amongst other tasks, to enable private key encryption on certificates. After the Windows Platform SDK has been installed, this tool is located in the same directory as makecert.exe and is named certmgr.exe. Assuming this directory is the system PATH environment variable, launch certmgr.exe either from within PowerShell, or at a command prompt as follows:

PS C:\Users\Administrator> certmgr

The Certificate Manager will open a window displaying a number of different categories of certificates. Navigate to the certificate to be protected (in the case of the example in this chapter select Personal -> Certificates -> PowerShell Cert as illustrated below:


The Windows Certificate Manager Tool


Right click on the selected certificate and select "All Tasks -> Export..." from the context menu to invoke the Certificate Export Wizard. Click Next on the Welcome screen to proceed to the Export Private Key page and select the Yes, export private key option. Click Next to proceed to the Export File Format screen and select the Personal Exchange Format option.

On the next screen, enter the password to be used to protect the key and click Next. Finally, specify a filename and location for the .pfx file (for the purposes of this example we will use the name cert.pfx. Click Next to display the summary screen. Review the summary information and click Finish to export the key.

The resulting pfx file subsequently be used access the certificate using the Get-PfxCertificate cmdlet as illustrated below. Before PowerShell will permit the script to be signed, however, the password entered during the export process must be entered:

PS C:\Users\Administrator> $certificate = get-pfxcertificate cert.pfx
Enter password:

Once extracted, the certificate may be used to sign scripts using the usual command:

PS C:\Users\Administrator> set-authenticodesignature ./t.ps1 $certificate


    Directory: C:\Users\Administrator


SignerCertificate                         Status                       Path
-----------------                         ------                       ----
3152D8D9584375916BB9A7511BF2E789F257AD0B  Valid                        t.ps1