Auditing Group Policy changes

Hi there, it's Jimmy from the Canberra office on managing and detecting changes to Group Policy. In this post I'm planning on discussing Group Policy, the Advanced Group Policy Management (AGPM) tool, and tracking/auditing changes to Group Policy. This post is written with Windows Server 2008 R2 in mind, but the concepts translate to other releases.

Background

Group Policy is highly configurable, and some settings might seem quite obscure without any context or history behind why the setting was implemented in the first place. You may have found yourself in the position where you are trying to figure out what purpose a particular setting has… "Why are we storing LM hash values? Anyone?". You might understand the implications of the setting, but it's another thing to know the implications of removing that setting if you don't know the history of why that configuration was introduced into the environment.

Advanced Group Policy Management (AGPM), a component of the Microsoft Desktop Optimization Pack for Software Assurance customers, is a system which helps administrators put greater control around Group Policy changes. Under AGPM, the Editor, Approver, and Reviewer roles can be delegated to users or groups. Changes can be submitted offline by those designated as Editor, introduced to production by Approvers, with oversight from Reviewers. This managed release of changes leaves a more visible audit trail. Looking at the history of a particular GPO, we can see the evidence of previous changes. In this example I'm logged in as the reviewer account Tom. Looking at the change history of a particular GPO, we see that Jo (Editor) just submitted a change, which Bill (Approver) just deployed to production. 

 What does the AGPM console look like? Actually, it extends the GPMC console with an additional Change Control screen.

Problem

One thing that is important to know is that a policy which is under the control of AGPM can still be modified outside of the AGPM interface by someone with the appropriate permissions. AGPM was not designed to enforce itself on an administrator who has permissions to make Group Policy changes, or to change the underlying physical structure of a Group Policy Object.

There are good reasons to want all Group Policy administration to be done through the AGPM interface. There is the obvious benefit of controlled deployment of changes. Also, any change to an AGPM-controlled policy which is made outside of the AGPM console is going to disappear when the next version of the controlled policy is published from the AGPM archive to production. That how it works.

Solution (but not really)

So how do we prevent administrators from making changes outside of the AGPM interface? That question has been answered really well by the AskDS geniuses in a post called Forcing Domain Admins to use AGPM (but not really) . If you're short on time, the moral of the story is that this is unsupported, easily circumvented, and should be unnecessary. The instructions are there if you've made up your mind, but definitely read the whole post before going ahead with this.

Solution

If you're stuck with this problem of Group Policy changes being performed outside of AGPM, then perhaps detection is just as useful as enforcement. You can certainly audit Group Policy changes, know that they have occurred, and educate appropriately. How do we audit changes to Group Policy? To answer that question, first we should understand what a Group Policy Object is and how it is stored. A Group Policy Object is stored and replicated as two distinct components, the Group Policy Container (GPC), and the Group Policy Template (GPT).

The Group Policy Container is essentially a stub which represents a GPO in Active Directory. For the full class definition see Group-Policy-Container class. As an example, here is a filtered list of the noteworthy attributes from a GPC in my lab:

Attribute Value
cn {51BA8C3F-C2E3-4CFE-B5D4-D4E7E2379041}
displayName Controlled Policy 1
distinguishedName CN={51BA8C3F-C2E3-4CFE-B5D4-D4E7E2379041},CN=Policies,CN=System,DC=Domain,DC=com
gPCFileSysPath \\Domain.com\sysvol\Domain.com\Policies\{51BA8C3F-C2E3-4CFE-B5D4-D4E7E2379041}
gPCFunctionalityVersion 2
gPCMachineExtensionNames [{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}]
gPCUserExtensionNames [{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}]
objectCategory CN=Group-Policy-Container,CN=Schema,CN=Configuration,DC=Domain,DC=com
objectClass top; container; groupPolicyContainer
versionNumber 262153

There really isn't much to the GPC. It is essentially a placeholder in AD, pointing to the actual location of the configuration data (gPCFileSysPath).  When a change is made to a GPO, you would expect to see the versionNumber attribute change. You may also see the gPCMachineExtensionNames and gPCUserExtensionNames attributes to change if different Client Side Extensions (CSE) are invoked.  If remembering GUIDs isn't your thing, Mark Empson maintains a Group Policy Client Side Extension List you might find useful.

That’s the Group Policy Container part covered.

One of the attributes of the GPC was the gPCFileSysPath attribute. This attribute points to a location in the replicated SYSVOL share, and ends with a GUID which uniquely identifies the GPO. This is the second component of a GPO, the Group Policy Template (GPT). The structure of the GPT folder is not set in stone, and depends on the CSEs defined in the GPC. Defining the CSE GUIDs (gPCSomethingExtensionNames) in the GPC, instructs the client which CSEs to load, which know what files they will need to load from the GPT to get their settings.

The physical structure of each individual CSE is a bit beyond the scope of a blog post, but as an example the Administrative Templates CSE stores its settings in the Registry.pol file. There are Technet articles for a lot of the default CSEs which describe the physical structure in depth.

For the purpose of this post, the important things to know about how group policy is stored is that all changes to a GPO will affect the GPC object stored in the directory, and the GPT folder stored in SYSVOL. If you can detect changes to those two things, then you can detect a change to Group Policy, which is what we are after. So let's start already!

We're going to implement some auditing of AD DS objects and also a portion of the file system. If auditing rules are triggered, then events will be logged to the event log. Once that happens, there are plenty of options in terms of monitoring/alerting when those events are raised. I'll leave that part up to you.

Please get comfortable with auditing in the lab before touching a production environment.

The following steps discuss the use of Advanced Audit Policy Configuration, which was integrated into Group Policy in Windows Server 2008 R2. The same can be achieved in Windows Server 2008, but not in group policy. If you are still on Windows Server 2003 R2, you can still achieve similar with Audit Policy, however there would be more "noise" introduced using the broader audit categories.

Enable auditing of changes to AD DS objects

  1. Open/create a GPO which applies to domain controllers
  2. Navigate to Computer Configuration/Policies/Windows Settings/Advanced Audit Policy Configuration/Audit Policies/DS Access
  3. Enable Audit Directory Service Changes for Success

 Audit GPC objects

  1. Open ADSIEdit and connect to the domain NC

  2. Navigate to CN=Policies,CN=System,DC=domain

  3. Open the Advanced security settings for the Policies container

  4. Open the Auditing tab

  5. Create a SACL entry which audits Everyone, applies to This object only, for Successful accesses of type Create groupPolicyContainer objects

  6. Create another SACL entry which audits Everyone, applies to Descendant groupPolicyContrainer objects for Successful accesses of type Delete and Modify Permissions

  7. Create a SACL entry auditing Everyone, applying to Descendant groupPolicyContainer objects performing Successful accesses of type Write versionNumber

Note: You may want to audit more than just the versionNumber attribute. You could audit attributes like the displayName, which would catch renames. Also the CSE attributes gPCMachineExtensionNames and gPCUserExtensionNames would also be good candidates as they could conceivably be manually edited. You could audit more... but only audit what you need.

Let's test a few scenarios with the current auditing and see what gets picked up...

Scenario: Creation of a GPO

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 10:08:55 AM
Event ID: 5137
Task Category: Directory Service Changes
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: A directory service object was created.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x11D5209

Directory Service:
 Name: Child.Domain.com
 Type: Active Directory Domain Services

Object:
 DN: CN={D93CF2DA-9613-4D75-9FB1-72ADD58C24E5},CN=Policies,CN=System,DC=Child,DC=Domain,DC=com
 GUID: {84351713-35d7-4e4a-8621-7a82e4c00997}
 Class: groupPolicyContainer

Operation:
 Correlation ID: {a632fc19-f733-497d-9d25-fcb211502f8c}
 Application Correlation ID: -

 

Scenario: Modify a GPO

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 10:09:35 AM
Event ID: 5136
Task Category: Directory Service Changes
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: A directory service object was modified.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x11D5634

Directory Service:
 Name: Child.Domain.com
 Type: Active Directory Domain Services

Object:
 DN: CN={D93CF2DA-9613-4D75-9FB1-72ADD58C24E5},CN=POLICIES,CN=SYSTEM,DC=CHILD,DC=DOMAIN,DC=COM
 GUID: {84351713-35d7-4e4a-8621-7a82e4c00997}
 Class: groupPolicyContainer
 Attribute: LDAP Display
 Name: versionNumber
 Syntax (OID): 2.5.5.9
 Value: 2

Operation:
 Type: Value Added
 Correlation ID: {339599aa-bac0-40eb-8197-a475c42dba31}
 Application Correlation ID: -

 

Scenario: Link a GPO

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 10:10:06 AM
Event ID: 5136
Task Category: Directory Service Changes
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: A directory service object was modified.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x11D5209

Directory Service:
 Name: Child.Domain.com
 Type: Active Directory Domain Services

Object:
 DN: OU=Best OU,DC=Child,DC=Domain,DC=com
 GUID: {f60f255b-ef37-413d-acd8-a8e91c5513ba}
 Class: organizationalUnit

Attribute:
 LDAP Display Name: gPLink
 Syntax (OID): 2.5.5.12
 Value: [LDAP://cn={D93CF2DA-9613-4D75-9FB1-72ADD58C24E5},cn=policies,cn=system,DC=Child,DC=Domain,DC=com;0]

Operation:
 Type: Value Added
 Correlation ID: {3c2b7442-e476-49b2-8f71-75414dfba574}
 Application Correlation ID: -

Note: That actually caught a change to the gPLink attribute of an OU. We didn't even add a SACL entry for that, so it is audited by default.

 

Scenario: Change "Applies to" permission of GPO

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 10:15:57 AM
Event ID: 5136
Task Category: Directory Service Changes
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: A directory service object was modified.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x11D8FA0

Directory Service:
 Name: Child.Domain.com
 Type: Active Directory Domain Services

Object:
 DN: cn={D93CF2DA-9613-4D75-9FB1-72ADD58C24E5},cn=policies,cn=system,DC=Child,DC=Domain,DC=com
 GUID: {84351713-35d7-4e4a-8621-7a82e4c00997}
 Class: groupPolicyContainer
 Attribute: LDAP Display
 Name: nTSecurityDescriptor
 Syntax (OID): 2.5.5.15
 Value: O:DAG:DAD:PAI(OD;;CR;edacfd8f-ffb3-11d1-b41d-00a0c968f939 ...output suppressed

Operation:
 Type: Value Added
 Correlation ID: {f583eeed-58c3-4856-b687-aac6425b0c67}
 Application Correlation ID: -

 

Scenario: Delete a GPO

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 10:16:17 AM
Event ID: 5141
Task Category: Directory Service Changes
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: A directory service object was deleted.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x11D5209

Directory Service:
 Name: Child.Domain.com
 Type: Active Directory Domain Services

Object:
 DN: CN={D93CF2DA-9613-4D75-9FB1-72ADD58C24E5},CN=Policies,CN=System,DC=Child,DC=Domain,DC=com
 GUID: {84351713-35d7-4e4a-8621-7a82e4c00997}
 Class: groupPolicyContainer

Operation:
 Tree Delete: No
 Correlation ID: {54f9d67c-b432-4030-a4ad-fad6af2afec2}
 Application Correlation ID: -

With that level of auditing, we get a good view of who is making changes to Group Policy using tools other than the AGPM interface. However it's not a watertight solution. It is possible (don't do it) that someone with the appropriate permissions could make direct changes to the GPT. That is, the file structure containing the appropriate settings. There would be no change to the GPC, and therefore our current audit settings would not detect any change. To audit the GPT, we need NTFS auditing.

For the purpose of my lab I'll make the following configuration changes:

Enable auditing of changes to file system 

  1. Open/create a GPO which applies to the domain controllers
  2. Navigate to Computer Configuration/Policies/Windows Settings/Advanced Audit Policy Configuration/Audit Policies/Object Access
  3. Enable Audit File System for Success

Set auditing on SYSVOL 

  1. Navigate to the %systemroot%\SYSVOL folder
  2. Open the properties of the domain folder and navigate to the Auditing tab
  3. Create a SACL entry which audits Everyone, applies to This folder, subfolders and files for Successful accesses of type Create files / Write data, Create folders / append data, Delete subfolders and files, Delete, and Change permissions.

Importantly, we don't want to audit anything relating to file read operations. Otherwise we could be seeing events logged every time group policy is applied to a workstation!

What would a resulting GPT change look like with this auditing in place?

Log Name: Security
Source: Microsoft-Windows-Security-Auditing
Date: 26/04/2012 11:24:20 AM
Event ID: 4663
Task Category: File System
Level: Information
Keywords: Audit Success
User: N/A
Computer: CDC2.Child.Domain.com
Description: An attempt was made to access an object.

Subject:
 Security ID: S-1-5-21-2393838236-744523273-2036655924-1106
 Account Name: Terrance
 Account Domain: CHILD
 Logon ID: 0x631A5

Object:
 Object Server: Security
 Object Type: File
 Object Name: C:\Windows\SYSVOL\domain\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Some GPT file.xml
 Handle ID: 0xf0

Process Information:
 Process ID: 0x88c
 Process Name: C:\Windows\System32\notepad.exe

Access Request Information:
 Accesses: WriteData (or AddFile) AppendData (or AddSubdirectory or CreatePipeInstance)
 Access Mask: 0x6

That’s about it. We can see that group policy changes are originating from the account of administrator Terrance, instead of the AGPM service account. You might choose some more exhaustive auditing to suit your requirements. Hope that helps!

Jimmy