Kerberoasting is a rather in-vogue and effective attacker technique within Active Directory (AD) environments that was first popularized by Tim Medin in his 2014 talk “Attacking Kerberos: Kicking the Guard Dog of Hades”[1]. To perform a Kerberoast attack, an attacker requests a Kerberos service ticket for an account with a service principal name (SPN) set, cracks the ticket offline to recover the plaintext credentials, then can use those credentials within the environment. This works because service tickets are encrypted using the credential material of the account tied to the SPN. The only requirement for this attack is that the attacker be authenticated to the domain. Because of the low barrier to entry and high success rate, methods for detecting Kerberoasting have gotten a lot of attention. However, preventing Kerberoasting outright receives much less attention. The best prevention option is to configure accounts with SPNs to be managed service accounts (MSA/sMSA) or the newer group-managed service accounts (gMSA)[2], as these will configure strong randomized passwords that are infeasible to recover offline through password cracking. In this blog, I will discuss a different approach to selectively preventing Kerberoasting that uses discretionary access control lists (DACL) to limit the number of accounts that can request service tickets.
Access Controls
Within Windows, some objects are “securable” [3], meaning they can have security descriptors [4]. A security descriptor provides information on the object and, more importantly, defines access controls for the object. These access controls can be either “system” access control lists or “discretionary” access control lists[5]. Each list is comprised of access control entries (ACEs)[6] that indicate which principals have what permissions for the object. System access control lists (SACLs) control what information is audited for which principals when interacting with the object. For example, a file with a SACL set to audit everything will trigger a 4656[7] event when opened. Discretionary access control lists (DACLs) control the access a principal has over an object. For example, a user cannot open a file with a DACL entry set to deny that user access.
Using DACLs for combating attacker behaviors, while underutilized, is not unheard of. As part of common domain reconnaissance, attackers will attempt to retrieve logon session information for systems on a domain; typically using tools like NetSess.exe and BloodHound. Prior to Windows 10 1607[8], any domain user could enumerate session information on any domain-joined system by default. The tool “Net Cease”[9] was released to help combat this. Net Cease works by modifying the DACL of the Lanman Server component responsible for serving this information to prevent access by non-administrative users. Another common attacker behavior is to attempt to move laterally to other systems in the domain. The infamous PsExec[10] helps to accomplish this by remotely creating a service on a target system that accepts commands from the attacker. John Lambert of Microsoft Threat Intelligence demonstrated here[11] that this can be prevented by modifying the DACL for the service control manager to prevent remote access.
Domain Object Securability
The list of securable objects[3] in Windows is fairly comprehensive and notably includes directory objects. Here is an example security configuration page for a computer in Active Directory:
The permissions tab represents the DACL and the Auditing tab represents the SACL. When adding a new ACE to the DACL, the object’s properties are listed and permission to read and write can be controlled individually.
This level of granularity allows administrators to, for example, prevent specific users or groups from reading specific properties of another domain object. In theory, one can apply an ACE to an account with an SPN to deny reading of the SPN property by other Active Directory principals. In practice, this becomes a matter of creating and applying such an ACE. The DACL user interface in programs like Active Directory Users and Computers (ADUC) does not include all properties, service principal names being one such property. Fortunately, this functionality is still exposed through programming interfaces. During my initial research on this topic, I discovered a Stack Overflow post from 2011 that showed an example of how to apply DACLs to SPNs. That post used PowerShell to add an ACE to an AD object via ADSI (Active Directory Service Interfaces)[13]. I adapted the code to the following:
This can be used to set an allow or deny entry on a DACL for an SPN. You will need write permissions over the object’s DACL to be able to make this type of change. To deny the “eagle” user access to the “spntarget” user’s SPN, run the following commands:
First, define the account that will be blocked from access as a .NET IdentityReference[14] and define the LDAP path for the account with the SPN (here “spntarget”’s name is “Test User”). Then, run the command while specifying the deny option. The ACE is returned after running successfully.
Scenario
The following scenario shows how this concept can be applied to prevent Kerberoasting. In this scenario, the attacker has just compromised a user’s credentials (“eagle”) and has domain access. The attacker has identified a target account with an SPN, “spntarget”.
The attacker pulls some basic information about the user using PowerShell Active Directory modules.
The attacker then performs a targeted Kerberoast using Rubeus[15] against the “spntarget” user.
At this point the attacker can take this result and attempt to crack it offline.
In the same scenario, we can apply a DACL to the service principal name beforehand that will prevent the compromised user from reading it.
When the attacker now tries to read the SPN via PowerShell AD or request the SPN via Rubeus, it will fail silently.
Here is the above scenario as a video:
ACE Ordering
Access control list entries are evaluated in the order they appear in the list. When a principal attempts to access an object with a DACL, their attempt is evaluated against the first item in the list then the second and so forth[16].
In the above image, the first DACL entry is a deny for the principal Andrew, so the thread, who’s token belongs the principal Andrew, is blocked from access. However, if that same entry were at the bottom of the DACL, the thread would be allowed access (shown below).
Windows maintains – but does not enforce – a preferred ordering[17] for ACEs. Explicit ACEs, meaning ACEs tied to specific principals and not inherited from a parent container, should be placed above inherited ACEs. Within each of those subsections, explicit vs inherited, deny ACEs should be placed before allow ACEs. Some APIs, such as SetSecurityInfo[18], include some or all of this ordering logic in them so the user does not need to handle the ordering themselves when adding an ACE to a DACL. However, other APIs do not (e.g. AddAccessAllowedAceEx[17][19]). It is important to be mindful of which methods are being used to create the ACE because of these discrepancies.
The ACE ordering is also important when implementing this type of Kerberoasting prevention. The specific implementation however will depend on the desired approach. Below are several high-level example approaches. Keep in mind that requesting SPNs is a legitimate and necessary function of an Active Directory environment, so these approaches attempt to limit access to the SPN, not prevent access entirely.
Approach 1: Block all except group
With this approach, read access is allowed for a specific group and all other principals are denied. Any principal in the “SPN Group” can read SPNs for all users. This DACL would be applied to all accounts with an SPN.
Approach 2: Approach 1 with silos
This approach takes the basic premise of the first approach, but silos access based on some arbitrary grouping. For example, breaking out access by purpose (HTTP, MSSQL). Possible groups could be based things like functionality (webservers, databases), department (marketing, sales), and application (sales application X). Each variant of the DACL would be applied to all accounts with an SPN in the grouping.
Approach 3: Specific principals
The previous approach can also be further limited to prevent SPN access by anyone other than specific principals. This is appropriate when a grouping is not needed. Each DACL would be applied to an individual account with an SPN.
When determining the approach to take, consider the size and complexity of the environment. Large, complex environments likely should use an approach similar to the first approach as the complexity required for other approaches could quickly get out of hand at scale. However, smaller and less complex environments can opt for the second and third approaches as they will be much more manageable. The biggest downside to any approach will be tooling. Custom tooling will be required, whether it is simple like the above PowerShell script, or something more involved.
Note: Not mentioned in the above approaches are more complex approaches that rely on advanced access control features as like conditional ACEs as this is outside the scope of this blog. If you are interested in reading about conditional ACEs (and dynamic access controls), see: 1[20], 2[21], and 3[22]
Closing Remarks
In this blog, I covered an approach to selectively blocking Kerberoasting activities. This approach is definitely not a panacea, but it can be used to help reduce the attack surface within an Active Directory environment. Further, the idea of defensive DACLs is ripe for discovery and I would recommend those with an interest in Active Directory security to get creative.
If you have any questions about this article, please feel free to reach out to me on Twitter @2xxeformyshirt.
References
[0] Windows Internal, Part 1 (7th Edition) pages 650 – 668
[3] https://docs.microsoft.com/en-us/windows/win32/secauthz/securable-objects
[4] https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptors
[5] https://docs.microsoft.com/en-us/windows/win32/secauthz/access-control-lists
[6] https://docs.microsoft.com/en-us/windows/win32/secauthz/access-control-entries
[7] https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4656
[8] https://blog.stealthbits.com/making-internal-reconnaissance-harder-using-netcease-and-samri1o/
[9] https://gallery.technet.microsoft.com/Net-Cease-Blocking-Net-1e8dcb5b
[10] https://attack.mitre.org/software/S0029/
[11] https://twitter.com/JohnLaTwC/status/802218490404798464
[12] https://stackoverflow.com/a/6291111
[13] https://docs.microsoft.com/en-us/windows/win32/adsi/active-directory-service-interfaces-adsi
[14] https://docs.microsoft.com/en-us/dotnet/api/system.security.principal.identityreference
[15] https://github.com/GhostPack/Rubeus
[16] https://docs.microsoft.com/en-us/windows/win32/secauthz/how-dacls-control-access-to-an-object
[17] https://docs.microsoft.com/en-us/windows/win32/secauthz/order-of-aces-in-a-dacl
[18] https://docs.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setsecurityinfo
[19] https://msdn.microsoft.com/library/Aa374951(v=VS.85).aspx
[21] http://www.frickelsoft.net/blog/?p=310

Evan Perotti
Evan specializes in technical security assessments including network penetration tests, purple teams, red teams, and cloud security. He has experience in a variety of industries including telecommunications, financial services, pharmaceuticals, and healthcare.
Evan maintains the internal SRA standards and methodologies for purple team projects.
Evan is a member of SRA’s internal Research and Innovation team where he works to research novel approaches to security problems as well as develop security tools and resources.
You must be logged in to post a comment.