One of your most important resources when dealing with Windows security is the Windows Security log. Analyzing the events in your systems' Security log can help you zero in on potential threats or track down security breaches. The problem is that you can easily become bogged down in all the information these logs contain. For example, in Windows 2000 and later domains, the Security log of each domain controller (DC) contains a complete record of domain accountrelated logon failures. But sifting through all your DCs' Security logs to find failure-related events and filtering those events' descriptions to target the failures that might indicate threats can be a daunting challenge.
I introduced you to LogParser, a command-line utility that can read and query event logs from systems running Win2K or better, in "LogParser," May 2004, InstantDoc ID 42174. I showed you the basics of LogParser's SQL-like SELECT statements, which filter information according to event-log fields (e.g., EventID, EventType, TimeGenerated), and I explained how to perform simple string manipulations and more advanced SQL constructs (e.g., subselects, distinct queries). I also promised to show you how to use the tool's Strings field to extract information from an event's description. Doing so eliminates a lot of the manual work in detailed analyses such as the one I just described.
You can use LogParser to scan your DCs' Security logs, extract instances of a particular event or events, then pull out specific information from within the events' descriptions. As an example, let's examine how you can use LogParser to simplify logon-failure analysis.
For this example, you need to scan the Security log and pull out events that have event ID 529 (logon failure: bad username or password). You then need to filter these events according to the Logon Type field in the events' descriptions. This field tells you more about the cause of the failed logon—for example, which failed logons were interactive logon attempts (i.e., attempts to log on at the computer's console—Logon Type 2), which were logon attempts from over the network (Logon Type 3), and which were attempts made by a service or scheduled task (Logon Type 4). Although the latter type of event might be of interest from an operations view, it probably doesn't indicate a security problem. Likewise, you can filter out failed interactive logons so long as the server is physically secure and you have other physical accesscontrol logs that you can use to evaluate systems' physical security.
First, to extract the description from all instances of event ID 529, run (on the monitored system) the command that Listing 1 shows. This command produces output that includes the EventID and Strings fields from each instance of event ID 529, as Figure 1 shows. Each line in the output represents an instance of the event; the columns represent the selected fields. The Strings field, which includes all the fields from within the event's description, delimits those fields by using the pipe (|) symbol. You can see by examining the output that Logon Type is the third field within the Strings column.
To filter for that field, you can use LogParser's EXTRACT_TOKEN function. This function requires three arguments: the source string from which you want to extract the token (i.e., field), the token's index, and the delimiter string (in this case, the pipe symbol). For example, the command that Listing 2, page 14, shows uses the EXTRACT_TOKEN function to extract from the Strings column the third field (shown as 2 because LogParser begins the index with 0), where each field is delimited by the pipe symbol. The query then uses the AS keyword to label the output column "LogonType." Figure 2 shows the resulting output. To further filter the Strings column and retrieve only the events that have a Logon Type of 3, run the command that Listing 3 shows. This command returns the time the event was generated (TimeGenerated) as well as the username of the account attempting to log on (token 0), the logon type (token 2), the computer from which the logon was attempted (token 5), and that system's IP address (token 11), for all instances of event ID 529 in which LogonType is 3. Figure 3 shows a sample of the resulting output.
The More the Merrier
Now that you have an idea of the type of query you need to run, you can modify the query so that it extracts information from multiple input logs. To do so, simply include in the FROM clause a comma-delimited list of all the logs you want to query. To specify logs on other computers, precede the log name with \\computername\. For instance, the command that Listing 4 shows provides a list of all occurrences of event ID 529 on the systems
To query all your DCs for failed network logons, you could hard-code the system names into the FROM clause, but doing so could cause problems if a DC were removed or provisioned. To avoid that situation, you can create a more sophisticated query that automatically includes or excludes DCs, as appropriate. To do so, you first need to retrieve a list of all the DCs in the domain. Web Listing 1 (http://www.winnetmag.com/windowssecurity, InstantDoc ID 43450) shows a script that iterates through your domain's Domain Controllers organizational unit (OU) and builds a comma-delimited list of the Security logs on all the DCs in the form that LogParser requires. You'll need to modify the VBScript script, DCList.vbs, by replacing the sample domain name, sto.local, with your domain name in the code at callout A. For example, if your domain's DNS name is europe.acme.com, you'd change the code at callout A to
Set domain = GetObject("LDAP://dc=europe; dc=acme;dc=com")
To run DClist.vbs, type
at the command line. The script creates a one-line batch file, SetDClist
.cmd, in the current directory. At the command line, type
to execute the batch file, which creates an environment variable called DClist, set to the list of DCs that DClist.vbs retrieves. After executing the batch file, you can test the list by typing
at the command line. You then can include the variable %DClist% in your LogParser commands. For example, the series of commands that Web Listing 2 shows runs the VBScript file, executes the batch file, then incorporates the DClist variable in a LogParser command that retrieves the TimeGenerated, EventID, and ComputerName fields, sorted by TimeGenerated, from all instances of event ID 529 in the Security logs of all the DCs in the domain.
Master Your Domain
After you run DClist.vbs and SetDClist.cmd, you can get down to business and build some queries to help you track important activity. To track all logon activity for your domain accounts, you can use events generated by the Security log's Account Logon category. Be aware that Win2K and later support both Kerberos and Windows NT LAN Manager (NTLM) authentication. Intruders might try to attack you through NTLM, so you need to monitor both types of authentication even if all your network computers run Win2K or later and don't typically use NTLM. Therefore, you'll need to analyze several sets of event IDs: one set for Kerberos, one set for NTLM on Windows Server 2003, and one set for NTLM on Win2K.
Let's begin by identifying failed logon attempts that used a valid username but a bad password. Systems that use Kerberos log these events as event ID 675 with failure code 0x18. The LogParser command that Listing 5 shows retrieves the date and time when these events occurred, the username of the account that attempted to log on, and the IP address of the system from which the logon was attempted, as Figure 4 shows.
Next, let's look for the same type of failed logons for systems that use NTLM. Windows 2003 logs event ID 680 for both successful and failed NTLM authentication events, so you need to be sure to look not just for event ID 680 but also for EventType 16 (Failure Audit Event), as well as error code C000006A in event ID 680's description (this code indicates that the logon failed due to a bad password). The query that Listing 6 shows finds these events and returns a report such as the one that Figure 5, page 16, shows. Win2K systems require a slightly different query. These systems dedicate event ID 681 to failed NTLM authentication events. They also log the decimal version (rather than the hexadecimal version) of the error code. Furthermore, the position of the username token is different in Windows 2003 and Win2K: in Windows 2003, the username is token 1, whereas in Win2K, it's token 0. You'll need to use the query that Listing 7, page 16, shows to extract information about NTLM authentication failures on your Win2K systems.
More to Come
The sample queries I've shown can help you automate the common (and menial) task of tracking failed logons caused by bad passwords. In a future article, I'll show you how to modify your LogParser queries further to get a variety of important security information.