Windows 2000's Windows Script Host (WSH) scripting infrastructure is a simple yet powerful environment for creating and hosting scripts. Used in combination with Win2K technologies such as Active Directory Service Interfaces (ADSI), Collaboration Data Objects (CDO), and Windows Management Instrumentation (WMI), WSH greatly enhances an administrator's scripting capabilities. Win2K's addition of thousands of scriptable COM objects made creating administrative scripting solutions even easier.
However, the arrival of the LoveLetter.vbs virus in May 2000 changed the perception of Windows scripting. Although the Windows community was happy to have a powerful scripting infrastructure with thousands of scriptable COM objects, this scripting facility also presented a security weakness: Virus writers could more easily create and distribute malicious code.
In October 2001, Microsoft released WSH 5.6 as part of Windows XP. WSH 5.6 introduces a security model that uses a new code-signing feature and enhanced control over script execution to reduce the risks from malicious code such as the LoveLetter.vbs virus. After some background about the underlying security technologies of this new security model, I walk you through a script that illustrates how to add a digital signature to your code and show you how to create policies to enforce WSH security.
Digital Signature Technology
Microsoft Authenticode technology, coupled with an infrastructure of trusted entities called public key infrastructure (PKI), provides the code-signing capability. Authenticode technology is a set of industry-standardbased developer tools that let software publishers attach to their programs and scripts digital signatures that include information about themselves and their code. PKI is a security model that offers businesses protection for their networks through the use of technologies such as public key cryptography, digital certificates, and security policies. Windows PKI is an integrated set of security components and services built into Windows OSs.
Although Authenticode technology doesn't guarantee that signed code is safe to run, a digital signature on a program tells users that the software publisher is a PKI participant, and as such, is less likely to be distributing harmful code. I won't discuss the details of Authenticode and PKI here, but you can obtain more information about these and other Microsoft security technologies by searching Microsoft's security Web site at http://www.microsoft.com/security/default.asp.
Obtaining a Certificate
Before you can add a digital signature to your code to guarantee its integrity and origin, you must obtain an appropriate digital certificate. A certificate is a data set that identifies an organization, a script developer, or some other entity. The certificate issuer, called a Certification Authority (CA), issues a certificate after verifying a certificate applicant's identity. The certificate's data set includes a public key. When you sign a script with your private key, other parties can verify your identity by retrieving your public key from the certificate contained in the script.
To obtain a certificate from a CA, you must meet the criteria for a commercial or individual publishing certificate and submit your credentials to a CA such as VeriSign or Thawte. Keep in mind that CA services aren't free. Also, make sure that obtaining a certificate from one of these companies doesn't conflict with your company's security practices. Verify that your company isn't already using a PKI and that it doesn't already have an external CA for its employees.
If you want to obtain a certificate just for testing purposes, you can install Microsoft Certificate Services, available in server versions of Win2K, and use it as your CA. (For instructions about how to install Certificate Services, refer to the Windows PKI documentation checklists at http://www.microsoft.com/windows2000/en/advanced/help/sag_sechecklist.htm.)But be sure to use the certificate it generates for internal use or testing purposes only. A certificate that an internal CA issues will have little value to external entities because they won't know or trust the CA. After you obtain your public/private key pair (i.e., your certificate) from Certificate Services, you can use the certificate to sign your scripts. When you run signed scripts in your test lab, Windows PKI will recognize and verify the signature.
After you install Certificate Services, you can request your certificate for code signing through the Microsoft Management Console (MMC) Certificates snap-in. Expand Console Root, Certificates - Current User, Personal. Right-click Certificates and select All Tasks, Request New Certificate, as Figure 1 shows. A wizard will guide you through the steps to get your certificate and will prompt you to enter a certificate-friendly name (i.e., the certificate display name). The wizard will ask you to choose a certificate template; select the CodeSigning template. If you don't see this template in the list, you must install it in your CA by opening the MMC Certification Authority snap-in and selecting the Certificate Template to Issue option. Your system saves the new certificate in your certificate store with a name that corresponds to your common name (CN).
Add a Digital Signature to Your Scripts
Now that you have a certificate for signing your script, let's look at a sample script that illustrates WSH 5.6's new code-signing feature. Listing 1 shows the Windows Script (WS) file SignScript.wsf. SignScript.wsf adds a digital signature to a script by using a set of command-line parameters. The script uses the XML command-line parsing feature—a new component of WSH 5.6—which makes writing command-line scripts easier.
When the script starts, it executes the lines at callout B to verify the presence of both the file and cert command-line arguments. (These two arguments are required; the store argument is optional.) Each test evaluates a Boolean value to determine the presence of the command-line arguments. For example, the expression
returns a Boolean value of True if the command-line argument cert is present. If one of these two switches is missing, the ShowUsage method (new with WSH 5.6), which callout C shows, uses the information contained within the
The file parameter accepts any WSH script name that has a .vbs, .js, or .wsf extension. The cert switch identifies the name of the certificate to use, which usually corresponds to the certificate holder's CN. Make sure that the selected certificate supports the code-signing feature. You can use the optional store switch to specify the certificate store to use. By default, the script selects the personal store (called My) of the user running the script.
To run SignScript.wsf with its required and optional parameters, type
C:\>SignScript.wsf /file:"HelloWorld.wsf" /cert:"LISSOIR Alain" /Store:"My"
where HelloWorld.wsf is the script to which you want to add a digital signature, LISSOIR Alain is the certificate, and My is the certificate store. When the mandatory command-line arguments are present, SignScript.wsf digitally signs the script named in the command line (i.e., HelloWorld.wsf). To sign the script, SignScript.wsf uses WSH 5.6's new Scripting.Signer object. This object uses several methods and properties, which Web Table 1 (http://www.winscriptingsolutions.com, InstantDoc ID 25644) shows, to support various signing features. As callout D shows, the SignFile method uses three properties that match the script arguments defined in the XML <runtime> tags. When the script invokes the SignFile method, the Scripting.Signer object uses the appropriate syntax, based on the script-file extension, to store the signature in the script to be signed. Figure 3 shows the syntaxes for WS, VBScript, and JScript scripts.
Using a script isn't the only way to sign code. You can also use the Digital Signature Wizard (signcode.exe) provided with the Authenticode tools, which you can download from http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/000/219/msdncompositedoc.xml.
Enforcing WSH Security
You need to force WSH to check the validity of signatures added to scripts. By default, WSH doesn't check signatures and will run unsigned scripts or scripts with an invalid signature, so signing your scripts without enforcing a validity check is useless.
Different versions of Windows offer different mechanisms to enforce WSH security: Win2K and Windows NT users must modify registry subkeys to set WSH security. Windows .NET Server (Win.NET Server) and XP users can use Software Restriction Policies (formerly known as WinSafer).
Enforcing security under Win2K and NT. In Win2K and NT, WSH has a set of registry subkeys that you can modify to enforce WSH security on a per-user or per-machine basis. For user settings, you use the HKEY_CURRENT_USER\Software\Microsoft\Windows Script Host\Settings registry subkey; for the machine settings, you use the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings registry subkey.
The data item you'll modify is called TrustPolicy. By default, its value is set to 0, which offers no digital signature checking. If you set the value to 2, your system will run only scripts with a valid digital signature. If you set the value to 1, when a user runs a script, WSH will display one of the following messages, depending on the state of the signature in the script:
- The started script doesn't contain any signature.
- The started script contains a signature but it has been tampered with.
- The started script has an expired signature.
- The started script contains a valid signature, but the certificate chain process terminated in a root certificate that isn't trusted.
The user can choose to terminate the script or override the prompt and run it.
Enforcing security under Win.NET Server and XP. You can use the same security mechanism with Win.NET Server and XP that you use for Win2K and NT. However, by default, Win.NET Server and XP use Software Restriction Policies, which you can set up by using the MMC Group Policy snap-in. To enable WSH to use Software Restriction Policies, use a registry editor to navigate to the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings\UseWinSAFER subkey and set its value to 1.
To use the TrustPolicy mechanism under Win.NET Server and XP, you first need to set the UseWinSAFER data item to 0. Note that under Win.NET Server and XP, the TrustPolicy data item isn't available by default; you must create it as a REG_DWORD data item under the same registry subkey. After you set the TrustPolicy value to 1 or 2, it behaves as it does in Win2K.
The default security level for Software Restriction Policies is Unrestricted. If you want to block execution of all unsigned scripts, you need to create four additional rules in Software Restriction Policies: three path rules to disallow execution of scripts that use extensions .vbs, .js, and .wsf, and one certificate rule to allow execution of signed scripts from a trusted source. The settings that Figure 4 shows will let only scripts signed by LISSOIR Alain run.
Putting It All Together
Microsoft's efforts to provide a simple and powerful infrastructure for creating administrative scripting solutions has also facilitated the creation and distribution of malicious code. With the release of WSH 5.6, Microsoft addressed this security weakness with a new digital code-signing mechanism that can help administrators reduce the threat of malicious code. Although using digital signatures is an excellent practice, it's useless unless administrators properly configure WSH to enforce signature verification and validation policies; by default, this security mechanism isn't activated. Moreover, script developers need to sign their scripts with a signature guaranteed by a certificate from a known CA to ensure that the person who runs the script can verify the trustworthiness of the script author.
WSH 5.6 ships with Win.NET Server and XP. You can also download it as a separate module for Win2K, NT 4.0, and Windows 9x from the MSDN Web site at http://msdn.microsoft.com/downloads/sample.asp?url=/msdn-files/027/001/733/msdncompositedoc.xml.