Welcome to MSDN Blogs Sign in | Join | Help

I've written twice (here and here) about the relationship between the "old" event IDs (5xx-6xx) in WS03 and earlier versions of Windows, and between the "new" security event IDs (4xxx-5xxx) in Vista and beyond.

In short, EventID(WS03) + 4096 = EventID(WS08) for almost all security events in WS03.

The exceptions are the logon events.  The logon success events (540, 528) were collapsed into a single event 4624 (=528 + 4096).  The logon failure events (529-537, 539) were collapsed into a single event 4625 (=529+4096).

Other than that, there are cases where old events were deprecated (IPsec IIRC), and there are cases where new events were added (DS Change).  These are all new instrumentation and there is no “mapping” possible- e.g. the new DS Change audit events are complementary to the old DS Access events; they record something different than the old events so you can’t say that the old event xxx = the new event yyy because they aren’t equivalent.  The old event means one thing and the new event means another thing; they represent different points of instrumentation in the OS, not just formatting changes in the event representation in the log.

Of course I explained earlier why we renumbered the events, and (in the same place) why the difference is "+4096" instead of something more human-friendly like "+1000".  The bottom line is that the event schema is different, so by changing the event IDs (and not re-using any), we force existing automation to be updated rather than just misinterpreting events when the automation doesn't know the version of Windows that produced the event.  We realized it would be painful but it is nowhere near as painful as if every event consumer had to be aware of, and have special casing for, pre-Vista events and post-Vista events with the same IDs but different schema.

So if you happen to know the pre-Vista security events, then you can quickly translate your existing knowledge to Vista by adding 4000, adding 100, and subtracting 4.  You can do this in your head.

However if you're trying to implement some automation, you should avoid trying to make a chart with "<Vista" and ">=Vista" columns of event ID numbers, because this will likely result in mis-parsing one set of events, and because you'll find it frustrating that there is not a 1:1 mapping (and in some cases no mapping at all).

Eric

 

 

 

I've written before on noise reduction in the Windows security event log.  I've also written to describe how object access auditing works.  But, I still get questions on how to reduce noise from object access events.  The other day I got that question, specific to Directory Service objects, on an internal discussion list so I thought I'd clean up the answer a bit and share it with the world.  In general the same is true for any type of object, although there are a few more knobs to control for DS objects.

Object access audit is generated when the system access control list (SACL) on the object matches the access that was performed on ALL of the following conditions:

  1. Object - the object that was accessed must have either an explicit or inherited SACL.  The access performed is compared against the ACEs in that SACL.
  2. Success or failure of activity - every audit access control entry (ACE) in a SACL will be either of type AUDIT_SUCCESS or AUDIT_FAILURE.  The access performed must match the access type of the ACE for the rest of the ACE to be considered.
  3. User account - the accessing user's token is compared against each ACE matching the access type.  If the user, or a group the user belongs to, matches the SID in the ACE, then an audit might be generated.
  4. Access - the access being performed must match the audited accesses in the access mask in an otherwise matching ACE.

The specific auditing algorithm is discussed here.

So the way to reduce the number of audit events (566 on Windows Server 2003, 4662 on Windows Server 2008, or one of the new DS Change events on Windows Server 2008) is to cause one or more of those conditions to fail, except in the specific cases that you care about.

The SACL which will generate the most audit events is "Everyone:Success & Failure:All accesses" on the domain head with OI,CI (object inherit & container inherit flags) for all object types.  This SACL matches all of the above conditions in all cases.  (Incidentally I think that this is pretty close to the default SACL- with the exception of failures- for Windows 2000 Active Directory installations, and SACLs are not updated when DCs are upgraded from version to version.  Windows Server 2003 has much more conservative SACLs for new installations of AD.)

To reduce noise, I offer the following suggestions, addressing each of the above conditions:

  1. Audit only the objects that you care about.  User accounts and groups already are well-audited with "Account Management" auditing, so don't audit them with DS access.  Perhaps audit OUs, or other DS objects.  Use the Object Type and attribute type restrictions that you have in DS Access auditing.  Also, in Windows Server 2008, you can affect auditing on a per-object basis by adjusting the SearchFlags attribute in the AD schema for the object.  SACLs are more easily reversed so are probably a more acceptable method of controlling audit for most organizations.
  2. Audit successful accesses only.  Failed accesses are common and are NOT indicative of any security problem; in fact many failures are not even explicit requests by the user but are just normal requests made by the OS, and the OS will re-try with less access if the operation fails.  In my experience failure auditing is primarily useful for troubleshooting, not for security.
  3. Audit the "Everyone" group.  Although this matches any user, you will not accidentally miss any accesses that you care about due to failing to audit a user account who has access to the objects in question.  The only time that you would NOT audit "Everyone" is if you had an application or service account which was very noisy; in that case you'd need to create a group with all accounts EXCEPT the noisy accounts, and audit that group.
  4. Audit only the accesses that you care about.  Specifically, read accesses occur much more often (in my experience, a conservative estimate is about a 100:1 ratio) than write accesses.  If you restrict your auditing to "write" type accesses (including change, delete, change permissions, create, etc.) then you will end up generating far fewer events.  Auditing for read access is very noisy.  If you must audit for reads, consider auditing fewer objects, perhaps only auditing reads on the container object instead of the objects in the container, or on one "interesting" object in any given container as a "canary".

 

I get the question fairly often, how to use the logon events in the audit log to track how long a user was using their computer and when they logged off.

As I have written about previously, this method of user activity tracking is unreliable.  It works in trivial cases (e.g. single machine where the user doesn't have physical access to the power switch or power cord), and it works most of the time in simple cases where there is good network connectivy and the user is not trying to evade detection.  If the user has physical access to the machine-- for example, can pull out the network or power cables or push the reset button-- and if the user is actively trying to evade time tracking, then the only reliable solution is to surreptitiously put a video camera (subject to local laws) in a place that can monitor the user's presence in front of the keyboard (yes I am aware of research done to track sound of keyboard clicks, etc.).

There is no way to instrument the OS to account for someone who just backs away from the keyboard and walks away.  The screen saver, if configured, will come on after a configurable delay since the last keypress or mouse movement.  Yes, if you know the SS delay then you could just work that into your calculations.  However the workstation does not lock until the screen saver is dismissed (some of you might have noticed that when you bump the mouse to dismiss the screensaver, sometimes you see your desktop for a fraction of a second- that’s because your machine isn’t locked while the screen saver is being displayed).  And the events don't tell you whether the workstation was locked or auto-locked so you don't really know whether to add in the screen saver delay factor.  Plus, prior to Windows Vista, there is no workstation lock event at all, only an unlock event, which is constructed in a way which makes it difficult to correlate with the original logon event.

So the bottom line is, I don't advocate or recommend this method for tracking the time a user spends at the keyboard.  If I were hypothetically called as an expert witness, I would testify that such a method is unreliable and trivially circumvented.  You have been warned, I've beaten that dead horse enough I guess.

Given that you are disregarding all my contrary advice, how are you going to accomplish this?

First, we need a general algorithm.

Use time (for a given logon session) = Logoff time - logon time

Now, what about the cases where the user powers off the machine, or it bluescreens, or a token leak prevents the logoff event from being generated, etc.?  We can use the BEGIN_LOGOFF event to handle token leak cases.  We can use the shutdown event in cases where the user does not log off.  And in case of crashes, the only event we can use is the startup event.  Note that each of these introduces increasing levels of uncertainty.

Logoff time = (logoff time | begin_logoff time | shutdown time | startup time)

This is good, but what about the time the workstation was locked?

Workstation lock time = unlock time - lock time
Total workstation lock time (for a given logon session) = SUM(workstation lock time)

How about remote desktop & terminal server sessions, and fast user switching?  You can connect and disconnect from logon sessions, during which time the user technically isn't using the computer.

Session idle time = session connect time - session disconnect time
Total session idle time (for a given logon session) = SUM(session idle time)

How about times when the machine was idle?  We can estimate that by looking at the time the screen saver was in place and adding the screen saver timeout.

Console idle time = (screen saver dismiss time - screen saver invoke time + screen saver delay)
Total console idle time = SUM(console idle time)

Putting all of this together and modifying our original formula, we get:

Use time (for a given logon session) =
   Logoff time - logon time
      - SUM(workstation lock time)
      - SUM(session idle time)
      - SUM(console idle time)

When we expand it, it is not quite so pretty: 

Use time (for a given logon session) =
   ( (logoff time | begin_logoff time | shutdown time | startup time) - logon time )
      - SUM(unlock time - lock time)
      - SUM(session connect time - session disconnect time)
      - SUM(screen saver dismiss time - screen saver invoke time + screen saver delay)

You have to be very careful that you only look at events that are properly contained chronologically between two other appropriate events, to avoid accidentally pairing the wrong logon and logoff events, or pairing a lock workstation event from one logon session with a different logon session.  The best correlation field is the Logon ID field, the next best are timestamp and user name.  At various times you need to examine all of these fields.

Now, which event IDs correspond to all of these real-world events?

They are all found in the Security event log.  The pre-Vista events (ID=5xx) all have event source=Security.  The Vista/WS08 events (ID=4xxx) all have event source=Microsoft-Windows-Security-Auditing.


512 / 4608  STARTUP
513 / 4609  SHUTDOWN
528 / 4624  LOGON
538 / 4634  LOGOFF
551 / 4647  BEGIN_LOGOFF
N/A / 4778  SESSION_RECONNECTED
N/A / 4779  SESSION_DISCONNECTED
N/A / 4800  WORKSTATION_LOCKED
* / 4801    WORKSTATION_UNLOCKED
N/A / 4802  SCREENSAVER_INVOKED
N/A / 4803  SCREENSAVER_DISMISSED

* prior to Windows Vista, there was no event for locking the workstation.  Unlocking the workstation generated a pair of events, a logon event and a logoff event (528/538) with logon type 7.  These events had the same user name as the "original" logon session and were completely enclosed chronologically by the logon/logoff events for the "real" logon session, but did not contain the Logon ID of the original logon session or other unambiguous correlator.  This makes correlation of these events difficult.

All of these events are generated in the Logon/Logoff audit policy category, although on Windows Vista and Windows Server 2008 they are scattered among the various subcategories in this audit policy category.  The audit event spreadsheet that Ned wrote has all the policy subcategory mappings as well as the event descriptions.

Sorry that this is more of a do-it-yourself than a solution-in-a-box, but this is pretty difficult to script and so far I haven't worked on a project that required this.

Eric

I get a lot of questions about how ACS event retention works.  So here you go, I'm blogging it so I can just answer with a link :-)

There are two DWORD registry values which affect backlog transmission.  Both are on the collector machine under HKLM\System\CurrentControlSet\Services\AdtServer\Parameters.

EventRetentionPeriod, if present, is expressed in hours (I forget the default).  It takes precedence over MaximumEventAge, which is in days (default=1).  Both of these values control the backlog of events that will be sent from agents to the collector on agent connect, but as mentioned, EventRetentionPeriod wins any conflict.  MaximumEventAge used to control database retention in early beta builds but does not anymore, since the database moved to a partitioning mechanism.  You might encounter MaximumEventAge if you are migrating from ACS beta to Operations Manager 2007 ACS.

Grooming is now governed entirely by the grooming algorithm.  The grooming algorithm is simple: partitions will be deleted by the next grooming job as soon as they are eligible for deletion.

Eligible for deletion means:

  • dtPartition.Status == 2 AND
  • dtPartition.LastCreationTime < (now() - (partitionDuration * numPartitions))

Think of (partitionDuration * numPartitions) as the retention period before data is groomed from the database. 

  • partitionDuration = dtConfig[5]
  • numPartitions = dtConfig[6]

Note that dtPartition[<partitionId>].LastCreationTime defaults to 12:00am 1/1/2000 (collector local time).  After successful execution of the close partition script, this field’s value is set to max(dtEvent_<partitionId>.CreationTime) for the partition in question.  There is an implication here that if you update status to 2 without updating LastCreationTime, then the partition is immediately eligible for grooming assuming your clock is accurate.

The partition switch offset (time of day to switch partitions) value in dtConfig has no effect on grooming, other than that grooming will not occur during a partition switch.

Grooming runs at startup and immediately after checkpointing.  The default checkpoint interval is 198 seconds but this interval can be configured  by the DWORD registry value CheckPointInterval on the collector, in the same location as the other registry values.  A successful checkpoint logs an event in the database, event ID 0 with a source of “_acs” (you might have seen these on an “idle” ACS and wondered how they got there…)

We got several reports recently of a bug in ACS that certain DS Access events, primarily for dnsNode and dnsZone objects, don't properly get looked up.

Some background: the event log in Windows prefers to log invariants such as message IDs, parameter message IDs, SIDs (security IDs which represent users and groups, etc.), and GUIDs (globally unique IDs which represent objects in Active Directory), rather than the actual names of the objects.  At view time the viewing application is expected to look up the name associated with the invariant and display it to the user.

The reasons that Windows does this are (1) that it enables localization, so that English speakers can see "Administrator" and French speakers can see "Administrateur", and (2) that it provides rename safefy- many objects are rename-able, such as domain accounts and other AD objects.

Anyway in ACS we had to solve the problem of how to store mountains of log data in a database, make it queryable in meaningful ways, preserve original format, present to users in a recognizable/understandable format, etc.

The way we chose to solve our several problems was to take strings that contained an invariant and append the translated name or string.

For example:
%{e0fa1e8c-9b45-11d0-afdd-00c04fd930c9}
would be translated to:
%{e0fa1e8c-9b45-11d0-afdd-00c04fd930c9}=”dnsNode”

and
%%7685
becomes:
%%7685=”Write Property”

As I mentioned, though, we ran into a problem recently.  Some of our customers were monitoring AD objects with ACS and noticed that ACS was not translating the GUIDs for certain objects.  When they manually looked up the GUIDs they noticed that they were for AD-integrated DNS objects.

After investigation, we found that AD was logging certain audit events for the objects, before all the attributes of the objects had been populated- DNS was populating the objects in multiple operations per object and each operation causes a separate event.  So ACS, which operates as close to real-time as we could get, was actually noticing the first event and asking AD "what's this?" before DNS had finished updating AD with things like the object's name.  The difference in time was literally only milliseconds.

Anyway I didn't really feel it was an ACS bug and wanted to file a bug against Windows DNS Server.  However the Operations Manager team has prototyped a configurable behavior for the ACS agent that lets it wait a very short time (configurable number of ms) and retry, when it fails to look up an AD object because the object doesn't exist.  This might be released as a public patch and/or in a future Service Pack.

I thought you might appreciate stories of the kinds of weirdness we run into.

A judge in New Zealand declined to convict the admitted (guilty plea) botherder of a million-bot botnet, citing the negative consequences a conviction would have on the young man's future prospects.  See the story here.

Well duh.  The whole theory of crime and punishment is that if you do something bad, you get punished, and punishment is something that is unpleasant, so you try to avoid it, hopefully by not doing the crime.  See?  One would hope that a judge would understand this concept.

I could understand if the judge said "this is just a stupid kid, he doesn't deserve to do 20 years", and gave the kid probation, community service and a big fine.  I don't know if New Zealand has such options, or if the judge has latitude in sentencing.  There is probably more to the story than is being told.  But you don't take over a million computers that don't belong to you, personally making tens of thousands of dollars, and not realize that you're doing something wrong.  Unless you're a sociopath.  And in either case, you either need punishment (for doing something you know is wrong) or separation from society for the protection of society while you get treatment (if you are a sociopath).  So whatever the case, the judge got it wrong, and as a result is practically encouraging future behavior of the same sort.

If you haven't used wevtutil.exe to script event log tasks in Windows Vista or Windows Server 2008, you're missing out.  The new tool makes getting events out of the log pretty easy, but the main thing is that it doesn't suffer from any of the drawbacks around getting field delimiting correct.

The tool's command to query events from a log is "qe", and takes a log name as a parameter.

If you want to specify a query expression, then you can use XPath with the /q switch.  The easiest way to do this is to use Event Viewer to build a filter for just the events that you want, and then copy just the XPath expression out of the XML tab of the filter dialog in Event Viewer.  Be careful to copy only the filter expression and not the XML that surrounds it. 

Finally, the default output format of wevtutil is XML.  However it dumps each event as XML, but does not include a root element- in other words it's not well-formed XML by default.  To include a root element you need to include the /e switch and a root element name.

I put this all together in a batch file, with an example XPath filter that just gathers interactive logon events (event ID=4624, logon type=2).  You can save this as a .cmd file and run it as an administrator on Vista or WS08 and it will pull up a list of your interactive logons in Internet Explorer (or your default XML handler application if you've changed the registration).  It has to run as admin because it accesses the security event log.

If you're really good (better than me, which is not hard) you could write an XSL style sheet and put this into a report format.

Good luck!

@echo off

 

REM (C) 2008 Microsoft Corporation

REM All Rights Reserved


set outputfile=%temp%\interactive-logon-events.xml


if "%1" NEQ "" set outputfile=%1

 

REM The next command is all one line and has no carriage returns

REM The only spaces in the XPath are around the AND keywords


wevtutil qe Security /q:"*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task=12544 and (EventID=4624)] and EventData[Data[@Name='LogonType']='2']]" /e:Events > %outputfile%


start %outputfile%


set outputfile=


 

I often talk about Ned, who is the current subject matter expert in Microsoft product support for the auditing feature in the US (Fadi is your guy in the Middle East and we have a couple of guys in Europe).  Well, Ned has a blog and I thought I'd point you guys there.  His recent posts on auditing include a description of how to deploy the special groups logon auditing feature with group policy.

 

Fadi, Ned and Brian of the auditing team have documented all the auditing events by audit policy category and subcategory for your reference.

Check it out in the Knowledge Base.

Even better, they documented all the events in spreadsheet format, and that's propagating to the Microsoft Download Center.  I'll publish the link when it's online.

2008-04-17 UPDATE:  Brian just sent me the link: here is the spreadsheet.

There's one topic that I know is on everyone's mind- no, not American Idol- it's "What's new in Auditing in Windows Server 2008?"

Well, funny that you brought that up.  My friend Jesper Johanssen just wrote a new book, the Windows Server 2008 Security Resource Kit, and he invited me to write a chapter about auditing for it, which I did.  So you, dear reader, are getting information straight from the horse's mouth, so to speak.

Anyway I think the book hits store shelves on March the 10th.  A number of distinguished individuals contributed to the book: Susan Bradley, Darren Canavor, Kurt Dillard, Roger Grimes, Brian Komar, Alun Jones and others.

I'd also like to send out special props to my auditing posse: Raghu (who was the primary developer for auditing for Vista & WS08) and Ned (who is the resident guru for auditing in Microsoft Customer Support Services), both of whom made significant contributions.  Raghu introduces the new "special group logon tracking" feature, and Ned contributed a spreadsheet mapping all the events (360-ish) to the policy category and subcategory and giving other key information about each event; this is included on the CD bundled with the book, along with an XML file defining the schema for all the events and event messages.  Ned's also working on getting a version of the spreadsheet available for download from the Microsoft download site.

In other news, the Windows Server 2008 Security Guide is also out, and yes, yours truly contributed in small part to the auditing guidance in there too, although I seem to have been overlooked in the credits (in all fairness my work delta from the Vista Security Guide was really small so maybe it did not meet their "credits bar").

Anyway, download the security guide and buy a copy of the book.  Buy more than one copy of the book, and give copies to your friends and loved ones.  Nothing says "Happy Anniversary, Honey" quite like a book or white paper about computer security.  OK, so maybe I should stick to computer security and stay away from relationship advice.  Flowers work well in my experience.

I've decided to start dumping my knowledge of ACS for posterity's sake.  My first installment is here, and it's an excerpt from an external email I put together which describes how event transformation works on ACS.

 

Transformation is performed on the agent (using instructions provided at connect time by the collector) and on the collector.  Transformation instructions are all stored on the collector in a file called EventSchema.xml which is in the AdtServer directory (%windir%\system32\security\adtserver).  This file is pointed to in the collector’s registry and is read during startup of the collector service; failure to successfully read and parse this file at startup is a fatal error for the collector (the debug log will complain about parsing).

 

The collector reads EventSchema.xml and builds in-memory binary tables of event transformation instructions and event string types by OS version/event log/event source.

 

The collector (as explained elsewhere) also reads AcsConfig.xml to get its persistent state and configuration for all known agents, to know what logs/sources to collect for each agent/agent group, etc.  This is all read into in-memory state for each agent.

 

At connect time, the agent sends version information- what the OS and agent version and service pack are, etc.  The collector first looks in its in-memory agent state to see what configuration applies to the agent.  Then it looks in its transformation tables and extracts the appropriate version-specific transformation instructions for the events that the collector is configured to collect from that agent.  Then it packages these instructions and sends them to the agent.

 

The agent starts reading events, transforming them according to its instructions from the collector, and sending the transformed events to the collector.  The collector finishes the transformation, services real-time subscriptions and loads the events into the database as appropriate.

 

If the agent encounters an event that is it configured to send (by log/source) but does not have transformation instructions for, then it simply builds a copy the event string for string and sends the copy of the event to the collector as an “unschematized” event.  The collector will handle this event without problems but will not extract non-header user fields (no primary/client/target user fields) and will not add string type information.

 

I’ll take Windows Server 2003 (build 3790), Event Log: Security, Event Source: Security, Event ID: 644 as an example.

 

Here’s the WS03 schema for 644 (excerpt from %systemroot%\system32\security\adtserver\EventSchema.xml in the path “Schema\Log[@Name=’Security’\Source[@Name=’Security’]\Version[@MinBuild=’3790’]\Event[@SourceId=’644’]”).

 

                        <Event SourceId="644" SourceName="SE_AUDITID_ACCOUNT_AUTO_LOCKED">

                              <Call Name="AppendString" Param1="1" Param2="0" />

                              <Call Name="AppendString" Param1="3" Param2="0" />

                              <Call Name="AppendString" Param1="2" Param2="0" />

                              <Call Name="AppendString" Param1="4" Param2="0" />

                              <Call Name="AppendString" Param1="5" Param2="0" />

                              <Call Name="AppendString" Param1="6" Param2="0" />

                              <Call Name="AppendSidFromNames" Param1="4" Param2="5" />

                              <Call Name="AppendNamesFromSid" Param1="3" Param2="0" />

                              <Param TypeName="typeUserDn" />

                              <Param TypeName="typeComputerName" />

                              <Param TypeName="typeTargetSid" />

                              <Param TypeName="typeClientUser" />

                              <Param TypeName="typeClientDomain" />

                              <Param TypeName="typeClientLogonId" />

                              <Param TypeName="typeClientSid" />

                              <Param TypeName="typeTargetUser" />

                              <Param TypeName="typeTargetDomain" />

                        </Event>

 

The instructions are all applied in order.  “Call” instructions are executed agent-side; “Param” instructions are executed server-side.

 

These instructions can be translated as:

 

·         Take string 1 from the original event and make it string 1 in the new event.  It is of type “typeUserDn”.

·         Take string 3 from the original event and make it string 2 in the new event.  It is of type “typeComputerName”.  Note that we are doing reordering here by appending original string #3 before original string #2.  Nifty, eh?

·         Take string 2 from the original event and make it string 3 in the new event.  It is of type “typeTargetSid”.

·         Take string 4 from the original event and make it string 4 in the new event.  It is of type “typeClientUser”.

·         Take string 5 from the original event and make it string 5 in the new event.  It is of type “typeClientDomain”.

·         Take string 6 from the original event and make it string 6 in the new event.  It is of type “typeClientLogonId”.

·         Take string 4 from the original event and treat is as a user name, and take string 5 from the original event and treat it as a domain name, look up the associated SID and make it string 7 in the new event.  The new string is of type “typeClientSid”.

·         Take string 3 from the new event, treat it as a SID, look up the user/domain name associated with it and append the user name as string 8 to the new event and the domain name as string 9 to the new event.  String 8 is of type “typeTargetUser” and String 9 is of type “typeTargetDomain”.

 

See the reordering?  Now here is an instance of the event with the original event data.  If you’re not familiar with the XML, it’s the XML output of Crimson, the new eventlog service introduced in Vista/WS08, but this is a WS03 [pre-Crimson] machine; we're looking at a saved event log (evt) file.

 

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">

  <System>

    <Provider Name="Security" />

    <EventID Qualifiers="0">644</EventID>

    <Level>0</Level>

    <Task>7</Task>

    <Keywords>0xa0000000000000</Keywords>

    <TimeCreated SystemTime="2007-12-17T15:50:14.000Z" />

    <EventRecordID>28003981</EventRecordID>

    <Channel>C:\Users\ericf\AppData\Local\Temp\SERVER34_SecEvts.evt</Channel>

    <Computer>SERVER34</Computer>

    <Security UserID="S-1-5-18" />

  </System>

  <EventData>

    <Data>user09</Data>                                                                                             // String 1 – user name

    <Data>SERVER34</Data>                                                                                       // String 2 – looks like a machine name, confirmed by string 4

    <Data>%{S-1-5-21-5998314728-109421381-169156293-611111}</Data>            // String 3 – definitely a SID

    <Data>SERVER34$</Data>                                                                                     // String 4 – definitely an account name (machine account)

    <Data>CONTOSO</Data>                                                                                       // String 5 – looks like a domain name

    <Data>(0x0,0x3E7)</Data>                                                                                     // String 6 – definitely a logon ID

    <Data>-</Data>                                                                                                       // String 7 – empty null string at the end of the event (ignored by ACS)

  </EventData>

</Event>

 

When the event arrives at the collector, type information is applied, and then the user fields (typePrimary*, typeClient*, typeTarget*) are extracted from the string data section and the strings that are left are re-numbered starting at 1 (no reordering occurs).

 

Here’s a chart of what the event looks like at the various points in the system.  The changes at each step are shown in red.

 

Original Event in Event Log

Client-Side Transformation at Agent

Server-Side Normalization (WMI/SQL output)

Field

Content Description (implicit)

Field

Content Description (implicit)

Field

Content Description (explicit)

 

 

Client User

 

Client User

typeClientUser

 

 

Client Domain

 

Client Domain

typeClientDomain

 

 

Client Sid

 

Client Sid

typeClientSid

 

 

Client Login Id

 

Client Login Id

typeClientLogonId

 

 

Target User

 

Target User

typeTargetUser

 

 

Target Domain

 

Target Domain

typeTargetDomain

 

 

Target Sid

 

Target Sid

typeTargetSid

String01

typeUserDn

String01

typeUserDn

String01

typeUserDn

String02

typeTargetSid

String02

typeComputerName

String02

typeComputerName

String03

typeComputerName

String03

typeTargetSid

String03

 

String04

typeClientUser

String04

typeClientUser

String04

 

String05

typeClientDomain

String05

typeClientDomain

String05

 

String06

typeClientLogonId

String06

typeClientLogonId

String06

 

String07

 

String07

typeClientSid

String07

 

String08

 

String08

typeTargetUser

String08

 

String09

 

String09

typeTargetDomain

String09

 

 

To finish off a description of transformation, there are 7 transformation functions, each of which can optionally take 2 integers as parameters.  Note that there is no “destination event” field specifier; all references are only to the original event.  That’s because when constructing the destination event, any data added to the event is always appended- it is constructed from beginning to end- so the implicit destination field is “at the end of the event as it is now”.

 

Function

Parameter 1

Parameter 2

Description

AppendString

Reference to a string parameter in the source event in the event log

Unused

Appends the referenced string to the event which will be sent to the collector

AppendStringFromTable

Reference to a constant string in the statically defined <Strings> table (1-based) in the relevant Source\Version element in EventSchema.xml

Unused

Appends the referenced constant string to the event which will be sent to the collector

AppendProcessNameFromPid

Reference to a string parameter in the source event in the event log (source string is expected to be a numeric process ID)

Unused

Looks up the process image path name for the referenced PID and appends it to the event which will be sent to the collector

AppendTimeFromDatetime

Unused

Unused

Not Implemented/No Action

AppendSidFromNames

Reference to a string parameter in the source event in the event log (source string is expected to be a user name)

Reference to a string parameter in the source event in the event log (source string is expected to be a domain name)

Looks up the SID for the account represented by the specified user and domain names, and appends the SID to the event which will be sent to the collector

AppendNamesFromSid

Reference to a string parameter in the source event in the event log (source string is expected to be a security ID)

Unused

Looks up the user name and domain name for the account represented by the specified SID, and appends the user name and the domain name as separate strings to the event which will be sent to the collector

AppendNumber

Unused

Unused

Not Implemented/No Action

 

Out of range params cause the transformation instruction to be ignored and skipped.  Non-integer params or other XML formatting/malformation problem (including non-UTF8 formatting) cause an EventSchema.xml parsing error at collector startup which in turn causes collector startup failure.

 

So that’s ACS transformation in a nutshell.  I hope this helps you guys understand ACS functionality a little better.

 

Shortly I will finish my write-up on AcsConfig.xml but that is a simple file and not too hard to figure out if you are into experimentation.

 

Here are some cool things that you can try with the event schema file if you are adventurous:

 

1.       Drop fields.  We have modified eventschema.xml successfully to cause it not to collect certain fields (e.g. logon GUIDs) of certain events:

                              <Call Name="AppendString" Param1="1" Param2="0" />

                              <Call Name="AppendString" Param1="2" Param2="0" />

                              <Call Name="AppendString" Param1="3" Param2="0" />

// try deleting a line here

// or, to preserve ordering of subsequent strings

// try replacing “AppendString” with “AppendStringFromTable (param1=1)”

                              <Call Name="AppendString" Param1="4" Param2="0" />

                              <Call Name="AppendString" Param1="5" Param2="0" />

                              <Call Name="AppendString" Param1="6" Param2="0" />


2. Add an event source.  Some caveats are:

·         You must have a unique, well-formed GUID for the new source

·         You have to get events of the new source into the log (try “AuthzReportSecurityEvent” from MSDN)

·         You have to modify AcsConfig.xml to tell the agent(s) to collect the new source

 

 

NB I have used the C/C++ comment syntax throughout this post but note that ACS does not support either C/C++ nor XML style comments in the XML config files it uses

Today I encountered something new in the logon event- I thought that was old hat and I knew all there was to know about that but I guess I was wrong.

The logon event (528/540 prior to Windows Vista, 4624 in Vista and Windows Server 2008) has a field called a Logon Type.  This is a code that is passed into the logon API that tells the authentication system in Windows which policy to check the logon against.  Windows has separate policy checks for network logons, interactive logons, etc., so that you can allow users to access a system in some ways but not in others.

The logon type code is, in C/C++ parlance, an enumerated value- it's an ordered list of numeric values, each with an associated name, and these are defined in a publicly available file in the source code (ntsecapi.h).  In the source code, the values are always referenced by name.

Today on one of the internal aliases someone actually found a logon event with a logon type of 0- I have never personally seen one of these before and 0 is not defined in the SECURITY_LOGON_TYPE enumeration, so I would have assumed that it was a bug- but it turns out that we are aware of this case and use it occasionally for system logons.

So there you are.

Well there has been a lot happening on my old project, ACS (Audit Collection Services, a feature of SystemCenter Operations Manager 2007).

Two more of our partners, Enterprise Certified and NetPro, have released compliance solutions on top of ACS.

Another of our partners with ACS-based compliance solutions, SecureVantage, has started a new blog where ACS is a frequent topic.

Anyway I'm pleased to see that ACS is becoming a successful platform and I'm happy to answer ACS questions!  To you ISV's out there, Joseph and I welcome your questions as well (if we aren't already talking to you).  Let us know who you are so we can stay in touch with you!

OK here's something I just remembered today.  I may be the last person who remembers this so it's important that I record this somewhere.

In the RTM bits of Windows NT 4.0, for the German language release only, someone snuck in a string resource into the auditing message file.  I'm guessing that it was one of our localization engineers, but I don't know- I was over in the support side of things at the time.  I stumbled across the message one day while looking at source code.

Here's Björn's momentous message:  "Björn grüßt den rest der welt".  Basically Björn says hi to everyone.  He's a friendly guy.

This is string resource zero in the message table resource- it's not a code resource, it's properly formed and it's not used by the code anywhere.  You would not know it exists unless you slog through source code (like me) or use a hex editor or string dumper to analyze binaries AND happen to be so bored that you pull out an NT 4.0 RTM German CD and examine msaudite.dll.  NT4 RTM CD's are pretty rare, btw, because we replaced them with slipstream SP1 CD's very shortly after release.

If I remember correctly somebody else came along in a later service pack and changed Björn's name to their own (maybe it was Ulli?  I can't remember and I'm too lazy to find the source- it requires a lot of effort to dig that far back).  I do remember that shortly thereafter there was a huge Easter Egg crackdown here at Microsoft probably brought to a head by the Excel 97 Flight Simulator.  Björn's message of goodwill to mankind was erased forever. 

I did a search using the Officially Santioned Search Engine and the other one too; evidently the internet has forgotten Björn's message.  But I still remember, Björn.

Anyway I thought you might like this bit of arcana.  If you are bored, have a hex editor and a German NT4 CD, knock yourself out...

I got the question last week, why there are so many logon failure events on Windows XP when it is not domain joined.

The short answer is, by design.  (Yes, bad design.)

The longer answer is that the shell team is working around the fact that there is no "tell me if this user account has a blank password" API.

When in a workgroup (not domain joined), Windows XP displays a welcome screen that has little pictures (called "tiles") for each user who is permitted to log on to the computer.

The shell team wanted the experience that when you click on a tile, that you will immediately be logged on if your password is blank (we have good data that a large percentage of home users have blank passwords).  They only want you to be prompted for a password if you actually have a password.  Fair enough, and it also helps with accessibility for people for whom typing is challenging.

The XP Welcome Screen, when it is initialized each time it is to be displayed, attempts to log on each user for which a tile will be displayed, using a blank password.  Users with non-blank passwords will cause failures in this case (other users will cause logon success events followed by logoff success events). [2007-11-21 correction]

The Welcome Screen uses the result of these logon attempts to decide whether to display a password box when you select a user's tile.  If the user has a blank password, they will be logged on instead of being prompted for a password.

Why are they logging on the account?  Well it turns out to be the easiest way to tell if your password is blank.  We don't have a "is your password blank" API- that would be a security disaster- and we would prefer that the shell team not go mucking about in the SAM, retrieving hashes and computing the blank password hash for each account so that it could compare them. 

I asked for this behavior to be changed prior to XP's release.  Specifically I asked that the blank password check be moved from Welcome screen initialization to tile selection- this would still cause logon failures but many fewer of them.  I was declined.  I asked for fixes to it in SP1 and SP2 and was declined.  At this point we will not be revisiting this "feature"; the Welcome Screen was redesigned to eliminate this problem.

The shell team who designed the Welcome Screen did not feel that auditing was a common scenario for workgroup machines, and I didn't (and still don't) have any business case to dispute that.

More Posts Next page »
 
Page view tracker