Security Changes in Windows Server 2003 WMI

In 2002, Microsoft undertook a Trustworthy Computing initiative to make the Windows platform more secure. The company put all new development on hold while developers reviewed their existing code for problems that could lead to security breaches. Many Windows Server 2003 components have benefited from the security initiative. For example, developers made changes at the Windows Management Instrumentation (WMI) COM/Distributed COM (DCOM) level. Most of these changes are fairly minor and affect primarily C++ programmers who use the WMI COM low-level interfaces, but some of these changes affect administrators and WMI scriptwriters. You need to be aware of these three changes:

Locking Down Asynchronous Scripts
An asynchronous WMI script has a main routine and a subroutine that's executed in parallel, or asynchronously, to the main routine. The subroutine performs some WMI operations, such as stopping a Windows service or handling an event that occurred during execution of the main routine. The new locking mechanism ensures that the callback of the asynchronous subroutine comes from an authorized entity. For a sample asynchronous script, see the GenericEventAsyncConsumer.wsf script explained in "Exchange 2000 SP2 WMI Updates," January 2003, http://www.winnetmag.com/microsoftexchangeoutlook, InstantDoc ID 27211.

Generally speaking, when a WMI client application performs an asynchronous operation or event, it first connects to the WMI process, winmgmt.exe. The application handles this connection at the COM level by executing the ConnectServer method, which the WbemScripting.SWbemLocator object exposes. As Arrow 1 in Figure 1 shows, the WMI client passes a pointer to winmgmt.exe during this step so that the WMI process can call the subroutine that the client implements when the action or event occurs (Arrow 2 in Figure 1 shows the subroutine call). The WMI client has some security settings (e.g., impersonation type, authentication level) that winmgmt.exe retrieves when required. The WMI process always attempts to call back the client subroutine with the same authentication level, as Arrow 2 in Figure 1 shows.

However, controlling the security level of the callback is impossible when the WMI client is a WMI script or a Microsoft Management Console (MMC) snap-in, when the client lacks the functionality to control the security settings of the process, or in pre-Windows 2000 environments (because the machine Local System account doesn't have a network identity in these environments). In such cases, when the WMI client invokes an asynchronous operation, the underlying WMI COM mechanisms start the unsecapp.exe application in a separate process on the client, as Arrow 1 in Figure 2 shows. This behavior is the same for all Windows versions.

Unsecapp.exe passes its own pointer to the client. The underlying WMI COM mechanisms then pass unsecapp.exe along with the WMI script's asynchronous operation call to winmgmnt.exe, as Arrow 2 in Figure 2 shows. The winmgmt.exe callback uses unsecapp.exe, as Arrow 3 in Figure 2 shows. Because the WMI script can't enforce callback security as a COM/DCOM WMI client can, unsecapp.exe accepts callbacks from anyone. Unsecapp.exe obviously presents a security risk because any process can perform the callback on behalf of winmgmt.exe. After accepting the callback, unsecapp.exe returns the callback to the WMI script at the subroutine level executed asynchronously, as Arrow 4 in Figure 2 shows. Note that unsecapp.exe is involved only during asynchronous operations. Synchronous and semisynchronous operations don't use the same mechanism. For more information about the differences, see "Making an Asynchronous Call with VBScript" and "Making a Semisynchronous Call with VBScript".

Locking down scripts in Windows XP, Win2K, and Windows NT 4.0. Microsoft has implemented a lockdown mechanism for unsecapp.exe in Windows 2003, but at the time of this writing, the company has no plan to implement a similar mechanism for earlier Windows versions. Thus, when you consider using asynchronous operations or event notifications in WMI scripts in XP, Win2K, and NT 4.0, you should take the following precautions:

If possible, use a synchronous or semisynchronous scripting technique instead of an asynchronous one.

If you absolutely must use an asynchronous scripting technique, make sure that the script doesn't use a powerful security context (e.g., an administrative security context) to perform a crucial operation (e.g., a system shutdown) in the subroutine that handles the asynchronous callback. You should restrict any type of script from being executed in the security context of an administrator whenever possible, but be extra careful with asynchronous scripts. If you implement an asynchronous scripting technique, you should implement access checks in the client code.

Keep in mind that although asynchronous scripts pose a risk, the security threat exists only during the lifetime of the application that's performing asynchronous operations or receiving asynchronous events. In addition, the security threat is proportional to the asynchronous script's security context and the type of operation that the subroutine executes.

Locking down scripts in Windows 2003. In Windows 2003, Microsoft created a wrapper for unsecapp.exe that plays the role of a security broker between the WMI client and winmgmt.exe to validate callbacks executed on the unsecapp.exe callback interface. The wrapper is disabled by default to ensure backward compatibility with legacy WMI asynchronous applications. WMI COM/DCOM applications can enable and disable the wrapper. Thus, you can require one WMI client application to authenticate the callbacks (i.e., enable the wrapper) and let another application use the default setting of Everyone (i.e., disable the wrapper).

However, WMI scripts can't enable and disable the wrapper, so you can't enforce the wrapper activation from the scripting environment. You must change a registry subkey value to enable the wrapper so that unsecapp.exe accepts only authenticated calls. Be aware that the setting is global for all applications and scripts. To require authenticated calls, change the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\CIMOM subkey's UnsecappAccessControlDefault value from 0 (which allows anonymous calls) to 1.

After you enable the wrapper, it intercepts every callback to unsecapp.exe to verify the identity of the component performing the callback. The wrapper extracts the client SID from the security token (as Arrow 1 in Figure 3 shows) when the client script submits the asynchronous operation to winmgmt.exe (as Arrow 2 in Figure 3 shows). When winmgmt.exe performs the callback to unsecapp.exe (as Arrow 3 in Figure 3 shows), the wrapper intercepts the callback to extract the caller's SID. The SID extraction implies a call to Active Directory (AD), which validates the existence of the caller's SID, as Arrow 4 in Figure 3 shows. Next, the wrapper compares the caller's SID with the client's SID, as Arrow 5 in Figure 3 shows. If they match, unsecapp.exe executes the callback to the client script, as Arrow 6 in Figure 3 shows. If the SIDs don't match, unsecapp.exe doesn't return the callback to the client subroutine.

Changing the registry value to enable the wrapper affects only asynchronous applications and scripts in environments that include pre-Win2K systems. A typical example is a WMI application or script running on a Windows 2003 member server (on which the lockdown mechanism has been activated) that accesses WMI information on a remote NT 4.0 server. Remember that in Win2K or later environments, the Local System account has an identity just as user accounts do, so Windows services can run in the machine security context rather than in a specific domain user's security context. In pre-Win2K environments, Local System has local credentials only and can't be resolved in a domain. Thus, it doesn't have a network identity, and the wrapper can't identify it.

Prohibiting a Null SD on a CIM Repository Namespace
A CIM repository namespace contains a set of classes related to a specific management area (e.g., Root\Directory\LDAP for AD, Root\SNMP for SNMP, Root\MicrosoftIISv2 for Microsoft IIS). Each namespace has an SD that describes the namespace security settings. By default, a namespace inherits its security settings and SD from the parent namespace at creation time. You can change the SD (and, therefore, the settings) by using the __SystemSecurity system class's SetSD method. (For information about the __SystemSecurity system class and its exposed methods, see "__SystemSecurity" at http://msdn.microsoft.com/library/en-us/wmisdk/wmi/_systemsecurity.asp.)

In Windows 2003, you can't set a CIM repository namespace SD to Null. In earlier Windows versions, if you set a child namespace's SD to Null, the child namespace inherits the parent namespace's SD (because the inheritance-blocking flag in an SD is equal to 0 when the security descriptor is Null, which enables the inheritance). By eliminating the ability to set a Null SD, Microsoft wants to prevent anyone from deliberately removing a namespace SD. Thus, an application can't change a child namespace's security settings to those of its parent namespace to gain access to the child namespace.

Removing the ADSI-WMI Extension
The ADSI-WMI extension lets you retrieve some WMI information from an ADSI computer object. The extension is available in XP, Win2K, and NT 4.0 (if ADSI and WMI are installed), but Microsoft removed it from Windows 2003 for two reasons:

The Trustworthy Computing initiative directs that only well-used components should be enabled to reduce the avenues of attack. (Microsoft determined that the ADSI-WMI extension wasn't heavily used, but you might be one of the few people who are using it.)

Although the extension isn't subject to any particular security threat, it requires high privileges to run.

The script in Listing 1 shows the information you can retrieve at the WMI level from the ADSI computer object on a pre-Windows 2003 computer. You need to provide only the computer's Lightweight Directory Access Protocol (LDAP) name. At callout A in Listing 1, the script retrieves the ADSI computer object that represents the specified computer. From the created ADSI computer object, the script uses the ADSI-WMI extension's WMIObjectPath property to retrieve the path of the WMI object that the ADSI object represents, as the code at callout B in Listing 1 shows. In this case, the WMI object's path includes the moniker

You can then use the WMI object's path to retrieve the Win32_ComputerSystem object that the ADSI computer object represents.

Alternatively, you can use the ADSI-WMI extension's GetWMIObject to retrieve the Win32_ComputerSystem object right away, as the code at callout C in Listing 1 shows. This method uses the WMI object's path behind the scenes.

Similarly, instead of retrieving an instance of the Win32_ComputerSystem object, you can establish a WMI connection to the computer that the ADSI computer object represents. Then, you can create an instance of any class in the Root/CIMv2 CIM repository by invoking the GetWMIServices method, which returns a SWbemServices object, as callout D in Listing 1 shows. (For more information about the SWbemServices object, see "SWbemServices" at http://msdn.microsoft.com/library/en-us/wmisdk/wmi/swbemservices.asp.)

On a Windows 2003 computer without the ADSI-WMI extension, you can't retrieve the WMI object's path from the ADSI computer object right away. You must first construct the WMI moniker because the ADSI object no longer provides it. To build this moniker, you must use ADSI to retrieve the DNS host name and computer host name, as the code at callout A in Listing 2 shows. With these two names, you can build the WMI moniker that the GetObject function needs to retrieve the WMI object, as the code at callout B in Listing 2 shows. You then can use this moniker to retrieve and display the WMI object's path, as the code at callout C in Listing 2 shows.

Like the workaround to retrieve the WMI object's path, the workaround to retrieve the Win32_ComputerSystem object uses the DNS host name and the computer host name to build the WMI moniker. As the code at callout D in Listing 2 shows, you again use the moniker with the GetObject function to retrieve the Win32_ComputerSystem object. You can then display all the Win32_ComputerSystem object's properties, as the code at callout E in Listing 2 shows.

The workaround to establish a connection to the WMI object differs from the other workarounds, although the basic concept is the same. To connect to any class object in the Root/CIMv2 repository, you must build a WMI namespace object. As the code at callout F in Listing 2 shows, a WMI namespace object path consists of the DNS host name of the computer to which you want to make a WMI connection and the Root/CIMv2 namespace. After you establish the WMI connection, you can request any instance of any class in the Root/CIMv2 namespace, such as the Win32_Service class.

After you establish the WMI connection, you might want to use the Win32_ComputerSystem object's __PATH property to retrieve the same WMI object path that the code at callout C retrieves. (Note that Windows 2003 and XP offer an alternative property, called the SystemProperties_ property, to retrieve the __PATH property. Earlier Windows versions must use the coding technique that the code at callout C in Listing 2 shows.) Why would you want to retrieve the path again? You can use it to retrieve the object paths of other objects associated with the Win32_Computer object, such as the Win32_Service object or the Win32_Processor object. (These associations are visible with WMI CIM Studio, which you can download from "WMI Administrative Tools" at http://www.microsoft.com/downloads/details.aspx?familyid=6430f853-1120-48db-8cc5-f2abdc3ed314&displaylang=en.)

Windows 2003's design was driven by many factors, and one of the most important was security. WMI is an important underlying technology for Windows management. Because WMI supports many powerful tasks (e.g., shutting down a system, changing the system configuration), keeping it secure is important. The Trustworthy Computing initiative resulted in WMI changes that affect both administrators and developers. Therefore, a move to Windows 2003 should prompt a careful analysis of and possibly some modifications to your existing work methods and previously developed scripts.