Moniker Security Settings
In many cases, the default security settings work just fine for the WMI moniker. In many example scripts, you will see the line impersonationLevel=impersonate. This line is often not needed because the default Distributed COM (DCOM) security setting for WMI on Microsoft Windows 2000, Windows XP, and Windows Server 2003 is set so the impersonation level is equal to impersonate.
Note  | When I first started using WMI in my scripting, I noticed numerous scripts had impersonationLevel=impersonate set, and it made me curious. After a lot of searching, I found the other levels. When I tried to change the security settings, the script failed. The reason? You cannot specify security settings when running local. They work only when you are connecting remotely to another computer. |
But what does that really mean? Why are there options we would not normally utilize? You can use four levels of impersonation: Anonymous, Identify, Impersonate, and Delegate. By default, WMI uses the Impersonate permission, which allows a WMI call to use the credentials of the caller. When the person calling the WMI script is a domain administrator, the script runs with domain administrator privileges. You can also use other impersonation levels, as described in Table 9-1.
Table 9-1. Impersonation LevelsMoniker | Meaning | Registry value |
---|
Anonymous | Hides the credentials of the caller. Calls to WMI might fail with this impersonation level. | 1 | Identify | Allows objects to query the credentials of the caller. Calls to WMI might fail with this impersonation level. | 2 | Impersonate | Allows objects to use the credentials of the caller. This is the recommended impersonation level for Scripting application programming interface (API) for WMI calls. | 3 | Delegate | Allows objects to permit other objects to use the credentials of the caller. This impersonation will work with Scripting API for WMI calls but might constitute an unnecessary security risk. | 4 |
If you decide to specify the impersonation level of the script, the code would look like the following:
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}")
Because Impersonate is the default impersonation level for WMI, the addition of the curly braces and impersonationLevel=impersonate code is redundant. If you want to keep your moniker nice and clean, and yet you feel the need to modify the impersonation level, you can do this easily by defining the impersonation level of the SWbemSecurity object. In practice, your code might look like the following:
Set objWMIService = GetObject("winmgmts:\\" & strComputer & wmiNS)
objWMIService.Security_.impersonationLevel = 4
In this code, the first line contains the normal moniker to make the connection to WMI. You use strComputer and wmiNS to specify target computers and the target namespace, respectively. Because you haven't specified an impersonation level, you're using the default Impersonate security setting. On the next line, you use the handle that came back from the GetObject command that was assigned to objWMIService, and you define ImpersonationLevel to be equal to 4. (Impersonation values are listed in Table 9-1.) Obviously, you could define a constant and set it to a value of 4 and then substitute the constant value for 4 in the script. ImpersonationLevel is a property of Security_. Security_ is a property of the SWbemSecurity object. The SWbemSecurity object is used to read or set security settings for other WMI objects such as SWbemServices, which is actually the object created when you use GetObject and the WMI moniker.
WbemPrivilege Has Its Privileges
To add elevated privileges, you need to add a privilege string in the space immediately following the impersonation level. These privilege strings correspond to the WbemPrivilegeEnum constants, which are documented in the Platform SDK. Some of the more useful privilege strings for network administrators are listed in Table 9-2. (There are 26 defined privileges in the Platform SDK, most of which are of interest only to developers writing low-level WMI applications.)
Table 9-2. Privilege StringsPrivilege | Value | Meaning |
---|
SeCreateTokenPrivilege | 1 | Required to create a primary token. | SeLockMemoryPrivilege | 3 | Required to lock physical pages in memory. | SeMachineAccountPrivilege | 5 | Required to create a computer account. | SeSecurityPrivilege | 7 | Required to perform a number of security-related functions, such as controlling and viewing audit messages. This privilege identifies its holder as a security operator. | SeTakeOwnershipPrivilege | 8 | Required to take ownership of an object without being granted discretionary access. This privilege allows the owner value to be set only to those values that the holder might legitimately assign as the owner of an object. | SeSystemTimePrivilege | 11 | Required to modify the system time. | SeCreatePagefilePrivilege | 14 | Required to create a paging file. | SeShutdownPrivilege | 18 | Required to shut down a local system. | SeRemoteShutdownPrivilege | 23 | Required to shut down a system using a network request. | SeEnableDelegationPrivilege | 26 | Required to enable computer and user accounts to be trusted for delegation. |
As you can see from Table 9-2, some of these privileges are rather intriguing. This being the case, how do you request them? Well, this is where your work gets a little interesting. If you're requesting the privilege in a moniker string, you use the privilege string listed in Table 9-2, but you have to drop the Se part and the Privilege part of the string. For example, if you want to request the SeShutdownPrivilege privilege in a moniker, you would specify the privilege as Shutdown, as illustrated in the following WMI connection string:
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate, (Shutdown)}")
Querying the security event log
1. | Open the \My Documents\Microsoft Press\VBScriptSBS\Templates\WMITemplate.vbs script in Notepad or another script editor and save it as YourNameReadSecurityEventLog.vbs.
| 2. | Declare a variable called dteDate to hold the desired date for your event log query. Also declare a variable called IntEvent to hold the event ID you wish to query. The two lines of code that do this are seen below:
Dim IntEvent 'event code to look for
Dim dteDate 'the date to search from in log
| 3. | Use the dateSerial function to convert three numbers into a date formatted number. This will be the date you wish to use as the basis of your query into the security event log. To limit the amount of information returned, use yesterday's date for the query. Assign the date that is returned from the function to the variable dteDate, as seen below:
dteDate = DateSerial(2006,04,22)
| 4. | Assign an event ID to the IntEvent variable. I used 576, which indicates a privilege escalation. An example of event 576 is seen in Figure 9-2.
IntEvent = "576" 'event code

| 5. | Edit the WMI query so that you are choosing everything from the WIN32_NTLogEvent class. Use the IntEvent variable to assign value to the EventCode property in the Where clause, and specify the "security" for the LogFile property. Use the funUTC function to convert the dteDate variable into a Coordinated Universal Time (UTC) formatted date type you can use with the TimeGenerated property to reduce the number of records returned from the script. The completed WMI query is listed below:
wmiQuery = "SELECT * FROM Win32_NTLogEvent WHERE EventCode = " & _
IntEvent & " and LogFile = 'security' and timegenerated > " & _
funUTC(dteDate)
Warning  | If you do not enclose the name of the log file in the WMI query within a single set of quotation marks, your query will fail. |
| 6. | Under the line that connects to WMI by using the moniker, create a security privilege object and use the addASstring method to add the SeSecurityPrivilege privilege to your script. This is required to allow you to read from the security log. The code below performs this task.
objWMIService.security_.Privileges.addASstring "SeSecurityPrivilege"
| 7. | In the Output section of the script, edit the existing WScript.Echo commands to echo out the TimeGenerated, Message, EventCode, and CategoryString properties from the WIN32_NTLogEvent class.
WScript.Echo "TimeGenerated: " & objItem.TimeGenerated
WScript.Echo "message: " & objItem.message
WScript.Echo "EventCode: " & objItem.EventCode
WScript.Echo "CategoryString : " & objItem.CategoryString
| 8. | Delete the two remaining WScript.Echo commands.
| 9. | Turn off On Error Resume Next.
| 10. | Copy the function contained in \My Documents\Microsoft Press\VBScriptSBS\Utilities\FunConvertUTC.vbs to the bottom of your script. You will need to modify it just slightly, because the date value needs to be encased in single quotation marks. Add a "'"& in front of the dateTime variable. Also add &"'" at the end of the dateTime variable. The completed function is listed below.
Function funUTC(mydate)
Dim dateTime
Set dateTime = CreateObject("WbemScripting.SWbemDateTime")
dateTime.SetVarDate(mydate)
funUTC = "'" & dateTime & "'"
End Function
| 11. | Save and run the script by using CScript. Your output will probably look something like the following:
TimeGenerated: 20060423193754.000000-180
message: Special privileges assigned to new logon:
User Name: NETWORK SERVICE
Domain: NT AUTHORITY
Logon ID: (0x0,0x3E4)
Privileges: SeAuditPrivilege
SeAssignPrimaryTokenPrivilege
SeChangeNotifyPrivilege
| 12. | Notice the TimeGenerated field is in UTC time format and is therefore difficult to read. To correct this, copy the \My Documents\Microsoft Press\VBScriptSBS\Utilities\Fun TimeFunction.vbs script and paste it at the bottom of your script. The function looks like the following:
Function FunTime(wmiTime)
Dim objSWbemDateTime 'holds an swbemDateTime object. Used to translate Time
Set objSWbemDateTime = CreateObject("WbemScripting.SWbemDateTime")
objSWbemDateTime.Value = wmiTime
FunTime = objSWbemDateTime.GetVarDate
End Function
| 13. | To clean up the output from the TimeGenerated field in the Output section of your script, modify the existing line to call the function to translate objItem.TimeGenerated. This is seen below:
WScript.Echo "TimeGenerated: " & FunTime(objItem.TimeGenerated)
| 14. | Save and run your script by using CScript. You will notice that the output now has a "normal" date and time format. If your script does not appear to run properly, compare your script with \My Documents\Microsoft Press\VBScriptSBS\ch09\ReadSecurityEventLog.vbs. You may also want to modify the date used in the query by editing the value of dteDate.
|
Adding reporting information
1. | Open the YourNameReadSecurityEventLog.vbs script in Notepad or another script editor and save it as YourNameReadSecurityEventLogHeader.vbs.
| 2. | In the Header section of your script, declare two variables, startTime and endTime, that will be used to hold the return value from the Timer function.
Dim startTime, endTime 'used with timer Function
| 3. | In the Reference section of the script, use the Timer function to assign a value to the startTime variable, as seen below:
| 4. | Under the For Each...Next loop, use the Timer function to assign a value to the endTime variable. On the following line, echo out the results of subtracting startTime from endTime, as seen below:
endTime = Timer
WScript.Echo "It took " & endTime-startTime
| 5. | Copy the function contained in \My Documents\Microsoft Press\VBScriptSBS\Utilities\funLine2.vbs to the bottom of your script. This function will look like the following:
Function funLine(strIn)
funLine = Len(strIN)+1
funLine = strIN & VbCrLf & String(funLine,"=")
End Function
| 6. | Under the ExecQuery line in the Worker section of your script, echo out the wmiQuery value. Then use the funLine function to underline some code that tells how many items are found as a result of your WMI query. The code to do this is seen below:
WScript.Echo wmiQuery & VbCrLf & funLine("There are " & _
colItems.Count & " Events related to eventCode " & IntEvent) & _
vbNewLine
| 7. | Save and run your script in CScript. If it does not run, then compare the results with the \My Documents\Microsoft Press\VBScriptSBS\ch09\ReadSecurityEventLogHeader.vbs. You may also want to modify the date used to perform the query by editing the value of dteDate.
|
|