This post is going to focus on using the system access control list (SACL) functionality to detect endpoint compromise on Windows hosts. The goal is to quickly, cheaply, and effectively detect anomalous activity on an endpoint without focusing purely on anomalous process and thread execution.
If you’re unfamiliar with SACLs, the concept is quite simple: Apply an audit access control entry (ACE) to an object (e.g. a file, registry key) which logs when that object is successfully or unsuccessfully (or both) accessed or modified by one or more principles. These events will, with appropriate configuration, generate event log entries that may be analyzed to identify post-exploitation activity.
Note: This particular blog post will only cover object access and manipulation SACL entries. There are many other uses for SACLs which I may explore in future posts.
Note: This is a very basic primer of ACEs, ACLs, and Security Descriptors. It is highly recommended you perform deeper research on these technologies to understand their nuance and internals.
Before we dig into deploying SACLs, we’ll cover a very basic and quick primer on access control lists (ACLs) and access control entries (ACE).
In the Windows world, an ACL is a list structure that can contain zero, one, or multiple ACE. Each ACE in an ACL describes a security identifier (SID) and specific access (or deny) rights allowed for that SID against a given object. For instance, an ACE can allow specific users to read/write/modify an object, while another ACE can deny access to the object altogether for other users.
ACLs are applied against securable objects, such as files, folders, registry keys, and kernel objects. While there are many documented securable objects, research has identified there are still many dozens of objects that remain undocumented.
An ACL can be one of two specific varieties: a discretionary access control list (DACL) or a system access control list (SACL). The DACL is primarily used for controlling access to an object, whereas a SACL is primarily used for logging access attempts to an object.
There’s a lot going on here, so we’ll look at a quick visual:
https://eneter.blogspot.com/2013/08/windows-security-wiki.html
We’ll first walk through the DACL. As noted in the above image, the DACL has both Access Denied and Access Allowed ACEs. When an attempt is made to access a securable objects, the system will check the ACEs specified in the object’s DACL and make a determination on whether access should be allowed or not.
This is referenced in the following diagram:
https://msdn.microsoft.com/en-us/library/cc246052.aspx
In this example, a process is attempting to access a securable object and the token is inspected and compared against ACE entries on the object’s DACL. As the SIDs specified in the access token match those specified in the ACE, access is granted.
This diagram also outlines the order of ACE evaluation when attempting to access an object:
We’ll next walk through the SACL, the often-ignored and underutilized friend of the DACL. Unlike the DACL, the SACL provides access to the Audit ACE. The audit ACE simply describes whether or not access to an object was allowed, denied, or both, and with what access was granted.
This will prove to be incredibly valuable for a few key reasons:
In summary: DACLs control what SIDs can access what objects, while SACLs tell you whether or not they were successful in their attempt to perform a given set of actions against that object.
There two defensive SACL primitives that we will use in this post:
These two object primitives can be easily applied to both file system and registry objects. These primitives are defined in powershell as follows:
# SACL Primitive for File Reads / Directory Traversals / Ownership Changes
$AuditUser = "Everyone"
$AuditRules = "ReadData, TakeOwnership"
$InheritType = "None"
$PropagationFlags = "None"
$AuditType = "Success"
$FileReadSuccessAudit = New-Object System.Security.AccessControl.FileSystemAuditRule($AuditUser,$AuditRules,$InheritType,$PropagationFlags,$AuditType)
# SACL Primitive for File Writes / Appends / Deletes / Ownership Changes
$AuditUser = "Everyone"
$AuditRules = "CreateFiles, AppendData, DeleteSubdirectoriesAndFiles, Delete, TakeOwnership"
$InheritType = "None"
$PropagationFlags = "None"
$AuditType = "Success"
$FileWriteSuccessAudit = New-Object System.Security.AccessControl.FileSystemAuditRule($AuditUser,$AuditRules,$InheritType,$PropagationFlags,$AuditType)
# SACL Primitive for Registry Key Value Sets / Key Creation / Key Writes / Ownership Changes
$AuditUser = "Everyone"
$AuditRules = "SetValue, CreateSubkey, WriteKey, TakeOwnership"
$InheritType = "None"
$PropagationFlags = "None"
$AuditType = "Success"
$RegistryWriteSuccessAudit = New-Object System.Security.AccessControl.RegistryAuditRule($AuditUser,$AuditRules,$InheritType,$PropagationFlags,$AuditType)
# SACL Primitive for Registry Key Value Sets / Key Creation / Key Writes / Ownership Changes
$AuditUser = "Everyone"
$AuditRules = "SetValue, CreateSubkey, WriteKey, TakeOwnership"
$InheritType = "ContainerInherit, ObjectInherit"
$PropagationFlags = "None"$AuditType = "Success"
$RegistryRecursiveWriteSuccessAudit = New-Object System.Security.AccessControl.RegistryAuditRule($AuditUser,$AuditRules,$InheritType,$PropagationFlags,$AuditType)
Note: You will need appropriate Windows event logging enabled for object manipulation event IDs to log. I recommend the audit settings specified here.
Now, we’ll walk through how to configure a SACL manually. This is ill-advised for any production deployment, but it’s important to know how to investigate and modify these by hand.
For this example, we’ll configure a SACL on a super secret filed called KFC_Recipe.docx with the object read primitive we described above. The goal will be to log any access to this file and then identify unusual access by investigating the events.
Our unprotected KFC Recipe. Shame.
This panel will detail any configured audit ACEs configured on the object. As we haven’t added an ACE, it will be empty. Let’s fix that.
We first need to specify a principal (SID) to audit.
This will audit all principals that access this object.
This will audit all principals that successfully or unsuccessfully read the file.
The final output of the audit ACE.
This process is substantially easier to deploy via powershell:
# SACL Primitive for File Reads / Directory Traversals / Ownership Changes
$AuditUser = "Everyone"
$AuditRules = "ReadData, TakeOwnership"
$InheritType = "None"
$PropagationFlags = "None"
$AuditType = "Success"
$FileReadSuccessAudit = New-Object System.Security.AccessControl.FileSystemAuditRule($AuditUser,$AuditRules,$InheritType,$PropagationFlags,$AuditType)
$FilePath = "$ENV:USERPROFILE\Documents\KFC_Recipe.docx"# Get the ACL with Audit ACEs
$Acl = Get-Acl $FilePath -Audit# Set the ACE
$Acl.SetAuditRule($FileReadSuccessAudit)# Apply the ACL
$Acl | Set-Acl | Out-Null
Now we’ll perform validation on this ACE to ensure it’s logging appropriately.
We’ll first test as an innocuous user by opening the document in Microsoft Word:
Opening the document in Word generates a 4663 Event (File System Object Access).
Looking at the windows event log reveals that a 4663 (File System Object Access) event was logged. In this event, we can see the Object_Name references the KFC_Recipe.docx file, and the Process_Name references WINWORD.exe (Microsoft Word).
Let’s now try to access this file via another process:
Malicious file copying the KFC_Recipe.docx file.
In this instance, I used a malicious file (C:\Windows\Temp\runsystem32.exe) to simply copy the KFC_Recipe.docx file to C:\Windows\Temp prior to exfiltrating it.
In this instance, the SACL worked and our malicious binary was logged attempting to access our sensitive document. We can now operationalize this data by looking for anomalous processes accessing this file.
Here are some examples of potential alerting and detection strategies that could be developed and exploited with appropriately configured SACLs:
Alerting and Detection Strategy: Identify when a non-browser process accesses sensitive browser files, databases, and folders.
SACL Primitive: Object Read
Baseline Activity: Browser processes (e.g. Chrome and Firefox) will routinely access these files.
Activity Caught: Interrogation of browser history, theft of browser cookies, theft of browser login data, etc.
Powershell.exe accessing Chrome History DB.
Alerting and Detection Strategy: Identify when a non-legitimate process accesses sensitive files, keys, and credential stores in a user’s home directory.
SACL Primitive: Object Read
Baseline Activity: Password vaults, SSH/SSH key manager binaries, GPG binaries, administration tools.
Activity Caught: Theft of SSH/GPG keys, theft of password vaults, theft of AWS/Azure credentials, etc.
Unusual process reading SSH keys.
Alerting and Detection Strategy: Identify malicious persistence — or malicious modification of legitimate persistence entries — in commonly-abused registry locations.
SACL Primitive: Object Write
Baseline Activity: Variable depending on software installation and behavior.
Activity Caught: Addition of new malicious binary run key entries, hijacking of malicious persistence entries, etc.
Legitimate persistence mechanism hijack by a malicious binary.
Alerting and Detection Strategy: Identify when there are malicious modifications to critical system security, logging, or protective controls.
SACL Primitive: Object Write
Baseline Activity: GPO activity, normal administrative changes.
Activity Caught: Modification of trust stores [PDF], modification of logging (e.g. commandline, powershell), manipulation of security tooling controls (e.g. sysmon configuration), etc.
Powershell logging disabled by a malicious binary.
There are a few protips that I’ve learned while deploying this across my home environment: