Thursday, July 5, 2012

PowerShell (v3) - Adding SACL Auditing to a File

Security, in Windows, can be a pretty large, complex subject, particularly from a developer's perspective. A few years ago I started exploring security, and, found some great resources. However, when I recently went to figure out how to add a SACL to a file for monitoring I came up short. So, the post below is an exploration of just what SACL's are and how to add them in Windows.

Security is controlled, in NTFS based file systems, on just a few key concepts. Two of the main concepts are: ACE's (access control entry) and ACL's (access control list). An ACE is a structure applied to an object indicated a specific right required by the object to be accessed. An ACL is a composite list of ACE's used to indicate the full permissions required/applied to an object. In short, an ACE belongs to an ACL; conversely, an ACL is composed of ACE's.

ACL's come in two flavors: 1) DACL (discretionary access control list) and SACL (system access control list). Keith Brown gives a great description of the two structures, in The .NET Developer's Guide to Windows Security,
The discretionary access control list (DACL) contains a list of permissions granted or denied to various users and groups. The reason it's called "discretionary" is that the owner of the object is always allowed to control its contents. Contrast this to the system access control list (SACL), over which the owner has no special control. In fact, the owner of an object isn't even allowed to read it. The SCAL is designed for use by security officers, and it specifies what actions will be audited by the system. I like to think of the SACL as the "Big Brother" bits.
In usage, SACL's are great for tracking who accesses a file. They provide a way to keep track of who works with a given object. One thing to note is that ACL's are not stored in the object, but, rather in the $MFT (master file table). For example, using Access Data's FTK Imager, you can see, below, two permission sets: 1) Take ownership and 2) Full permission.

Full permissions - explorer properties

Full permissions - FTK Imager ($MFT) view

Take ownership - explorer properties

Take ownership - FTK Imager ($MFT) view

When you start working with PowerShell, the Access Masks are displayed in terms of .NET enumerations. Below is a quick example to create a new file and return the SACL (Audit) permissions of the file listed above.

# Start afresh

# Create new directory if it doesn't already exist
if(!(Test-Path ($path = 'C:\test')))
      md $path

# Pipe dir contents to test.log
dir C:\ > ($file = "$path\test.log")

# Get ACL information for new file
Get-Acl $file -Audit | select *
When I run this I get the following output in PowerShell:
PSPath                  : Microsoft.PowerShell.Core\FileSystem::C:\test\test.log
PSParentPath            : Microsoft.PowerShell.Core\FileSystem::C:\test
PSChildName             : test.log
PSDrive                 : C
PSProvider              : Microsoft.PowerShell.Core\FileSystem
Audit                   : {}
AccessToString          : BUILTIN\Administrators Allow  FullControl
                          NT AUTHORITY\SYSTEM Allow  FullControl
                          BUILTIN\Users Allow  ReadAndExecute, Synchronize
                          NT AUTHORITY\Authenticated Users Allow  Modify, Synchronize
AuditToString           :
Path                    : Microsoft.PowerShell.Core\FileSystem::C:\test\test.log
Owner                   : BUILTIN\Administrators
Group                   : DOMAIN\Domain Users
Access                  : {System.Security.AccessControl.FileSystemAccessRule, System.Security.Ac                          cessControl.FileSystemAccessRule, System.Security.AccessControl.FileSys                          temAccessRule, System.Security.AccessControl.FileSystemAccessRule}
Sddl                    * O:BAG:DUD:AI(A;ID;FA;;;BA)(A;ID;FA;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1301bf;;;AU)S:AI(AU;SA;WO;;;S-1-5-21-1234567890-1234567890 -1234567890 -1000)
AccessRightType         : System.Security.AccessControl.FileSystemRights
AccessRuleType          : System.Security.AccessControl.FileSystemAccessRule
AuditRuleType           : System.Security.AccessControl.FileSystemAuditRule
AreAccessRulesProtected : False
AreAuditRulesProtected  : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical  : True
What is important to note here is the Sddl values. For more information on SDDL, check out this link:
Understanding SDDL Syntax
As I start playing around with Get-Acl and the various options I wanted to know what all was available to work with, so, I did a Get-Member:
Get-Acl C:\test\test.log |
Get-Member |
ft name,membertype -AutoSize

Name                                MemberType
----                                ----------
Access                            CodeProperty
Group                             CodeProperty
Owner                             CodeProperty
Path                              CodeProperty
Sddl                              CodeProperty
AccessRuleFactory                       Method
AddAccessRule                           Method
AddAuditRule                            Method
AuditRuleFactory                        Method
Equals                                  Method
GetAccessRules                          Method
GetAuditRules                           Method
GetGroup                                Method
GetHashCode                             Method
GetOwner                                Method
GetSecurityDescriptorBinaryForm         Method
GetSecurityDescriptorSddlForm           Method
GetType                                 Method
ModifyAccessRule                        Method
ModifyAuditRule                         Method
PurgeAccessRules               :         Method
PurgeAuditRules                         Method
RemoveAccessRule                        Method
RemoveAccessRuleAll                     Method
RemoveAccessRuleSpecific                Method
RemoveAuditRule                         Method
RemoveAuditRuleAll                      Method
RemoveAuditRuleSpecific                 Method
ResetAccessRule                         Method
SetAccessRule                           Method
SetAccessRuleProtection                 Method
SetAuditRule                            Method
SetAuditRuleProtection                  Method
SetGroup                                Method
SetOwner                                Method
SetSecurityDescriptorBinaryForm         Method
SetSecurityDescriptorSddlForm           Method
ToString                                Method
PSChildName                       NoteProperty
PSDrive                           NoteProperty
PSParentPath                      NoteProperty
PSPath                            NoteProperty
PSProvider                        NoteProperty
AccessRightType                       Property
AccessRuleType                        Property
AreAccessRulesCanonical               Property
AreAccessRulesProtected               Property
AreAuditRulesCanonical                Property
AreAuditRulesProtected                Property
AuditRuleType                         Property
AccessToString                  ScriptProperty
AuditToString                   ScriptProperty
There's quite a bit to work with, so, I decide to try and map out some options in order to figure out how to manually create a SACL. This link helps me get a few starting steps:
How to Handle NTFS Folder Permissions, Security Descriptors and ACLs in PowerShell 
To get a more explicit breakdown of what I am working with currently, I run this command:
get-acl C:\test\test.log -audit | select -ExpandProperty access

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : ReadAndExecute, Synchronize
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : Modify, Synchronize
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None
This helps me connect the dots I see with this post:
Is there a way to create ACL's from scratch in powershell, as opposed to copying existing ones and modifying them?
Specifically, I want to focus on the AddAuditRule method of the member set. Using the information listed above, I can see the various objects I need to focus on. MSDN provides details, in particular, about the objects, one by one, as designated by the System.Security.AccessControl.FileSystemAuditRule class:
 FileSystemAuditRule Constructor
There are, in .NET 4.0, four overrides. Working from the first example above, we will explore the objects we need to focus on:
FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None
Based on this list, we have the following objects:

  • System.Security.AccessControl.FileSystemRights - FileSystemRights Enumeration
  • System.Security.AccessControl.AccessControlType - AccessControlType Enumeration
  • System.Security.Principal.NTAccount - IdentityReference Class
  • System.Security.AccessControl.Authorization.IsInherited - AuthorizationRule.IsInherited Property
  • System.Security.AccessControl.InheritanceFlags - InheritanceFlags Enumeration
  • System.Security.AccessControl.PropagationFlags - PropagationFlags Enumeration
Working from this list, and, the example above, I was able to identify, based on the FileSystemAuditRuleConstructor, only three of these objects are needed to create a new ACE:
  • FileSystemRights
  • IdentityReference
  • AuditFlags
From here, I was able to create the following example which added a SACL to my test file:
# Get ACL prior to script for reference
Get-Acl C:\test\test.log -Audit |
Format-Table SDDL -AutoSize -Wrap
which returns this:
Now, as I walk through my steps,
# Declare SACL structure
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]::FullControl
$IdentityReference = New-Object System.Security.Principal.NTAccount("$($env:computername)\test"),o:p>
$AuditFlags = [System.Security.AccessControl.AuditFlags]::Success

# Create new ACE
$Ace = New-Object System.Security.AccessControl.FileSystemAuditRule($IdentityReference, $FileSystemRights, $AuditFlags)

# Get ACL
$Acl = Get-Acl -Path C:\test\test.log

# Add ACE to ACL

# Set ACL
Set-Acl -Path C:\test\test.log -AclObject $Acl
I am able to set the exact SACL properities I need, and, apply them. To verify I have added exactly what I need, I rerun my initial Get-Acl cmdlet:
# Get ACL prior to script for reference
Get-Acl C:\test\test.log -Audit |
Format-Table SDDL -AutoSize -Wrap
and see my new SACL:
O:BAG:DUD:AI(A;ID;FA;;;BA)(A;ID;FA;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1301bf;;;AU)S:AI(AU;SA;FA;;; S-1-5-21-1234567890
Breaking down the last portion of the SDDL (S:AI(AU;SA;FA;;; S-1-5-21-1234567890
-1234567890-1234567890-1000), based on the ACE header template, we have the following components:

  • ace_type: 
    • AceType: AU 
  • ace_flags: 
    • ACE flags string: SA
  • rights: 
    • Access rights string: FA 
    • Access right value: FILE_ALL_ACCESS
  • object_guid: none
  • inherit_object_guid: none
  • account_sid: S-1-5-21-1234567890-1234567890-1234567890-1000
  • resource_attributes: n/a
Without getting into an in-depth exploration of specific combinations of the Security namespace, one of the key things to be aware of is the variety of options you have for adding SACL's; files are not the only objects which can be audited. Below is a list of additional object types which can be set up with SACL monitoring:
  • Directory service objects
  • File objects
  • Registry keys