Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Manual LDAP Querying: Part 2

2 May 2024 at 11:01

This post is a follow-up to my previous post on manual LDAP querying. I would highly recommend reading that post prior to reading this one if you are interested in some of the basics of searching LDAP.

A few people asked why I chose dsquery and ldapsearch for the last blog. There are several options for querying LDAP, but dsquery and ldapsearch were the tools I was most comfortable with. Additionally, dsquery being signed binary, it is easy to get on target without being flagged. Similarly, with ldapsearch, it is easily installed and is sometimes already present on hosts and it can be run through SOCKS proxies. For this blog, I will show less examples for conciseness, but remember the focus is how to query with LDAP filters. The important item to focus on is the LDAP filters themselves.

Many tools that query LDAP have a way for you to create custom filters baked in. Therefore, if you understand how to create LDAP filters, you can use any tool that allows you to create your own custom LDAP filter. While this blog focuses on querying in a Windows Active Directory (AD) environment, LDAP queries can work in other forms of directory services.

For this blog, I will focus on items not covered in the previous blog as well as discuss some of the complexities of manually querying. The goal is to try to get a more accurate understanding of an AD environment and recognize some of the common issues that can arise from querying manually.

Combination Filters

One important item not included in the first blog was how to create compound filters with an OR operator. A compound filter with an OR operator will look like this:
"(|(attribute1=value1)(attribute1=value2))"

In this filter, the “|” indicates that it is a combination filter, and any results should have “value1” or “value2” for attribute1. As with other filters, these operators can be combined with others to create more complex queries.

dsquery * -filter "(&(objectClass=computer)(|(name=*WIN-10*)(name=*WIN-11))(!(description=*HIPAA*)))"

The image and query listed show how these different operators can be used in a combination filter. Here, we are using the AND (&), OR (|), NOT (!), and wildcard (*) operators to create the query. The plain language explanation for this filter would read, “I want all of the computer objects that have WIN-10 or WIN-11 in the name but do not have HIPAA in the description.” When you are creating these queries, keep in mind that the parentheses do matter and if you do not close them correctly, your query may fail or give you inaccurate results.

dsquery * -filter "(&(objectClass=computer)(|(name=*WIN-10*)(name=*WIN-11)(!(description=*HIPAA*))))"

This is one example of how the parentheses can affect your results. In this example, the parentheses around the OR statement were moved to include our not parameter. In plain language, the way this is interpreted is, “I want all of the computer objects that have WIN-10, WIN-11, or does not have HIPAA in the description.” The JZOID-WIN-10, which should have been excluded because it contains HIPAA in the description, was included in the results because it met the WIN-10 parameter in the OR statement while others which do not have WIN-10 or WIN-11 were included because they do not have HIPAA in the description.

Nested Groups

Nested groups occur when one group is added as a member of another group. This is a common practice but can create additional complexities and unforeseen results. It can also make it harder to find what you are looking for when you are trying to understand permissions in an environment because permissions inherit down to nested members of a group. Here I will show why it is important to check for nested groups. In this first screenshot, the query is looking for any users who are members of the Domain Admins group.

dsquery * -filter "(&(objectClass=user)(memberOf=CN=Domain Admins,CN=Users,DC=PLANETEXPRESS,DC=LOCAL))"

However, when we look at the same group through the administrator view, we see there is a group nested within the Domain Admins groups.

This group did not show up because our query is looking for users who are members of the Domain Admins group, not groups who are members of the Domain Admins group.

This next block is a query which filters on the memberOf attribute of the Domain Admins group. This returns the Security group, but does not show who the members are who may also be part of the Domain Admins group.

dsquery * -filter "(&(objectClass=group)(name=Domain Admins))" -attr member

From this information, you could further expand and query who the members of the Security group are, as shown below.

dsquery * -filter "(&(objectClass=group)(name=Security))" -attr member

One option for getting a more precise list of group membership would be to ensure that your filter is not being too restrictive. While usually we want to be as specific as possible to reduce the number of results that must be evaluated, this query is an example of how making a query too specific of a filter can give inaccurate results.

dsquery * -filter "(memberOf=CN=Domain Admins,CN=Users,DC=PLANETEXPRESS,DC=LOCAL)"

By not specifying an object class in the query, we will get a list of both the users and groups that are members of the group.

Alternatively, using a combination of dsquery and dsget (which is also a signed binary and available on many servers), we can get the nested members of the group. Here we can now see that the user Turanga Leela is a nested member of the Domain Admins group.

dsquery group -samid "*Domain Admins*" | dsget group -members -expand

While dsget is outside of the scope of LDAP filters, it works here to show an example of how information can be obscured when using LDAP filters. This example shows some of the complexities of manual querying and why it is important to be thorough when you are doing manual investigation. Nested groups are an item you want to look for in an assessment. While it is much easier to visualize with tools such as BloodHound, mapping it out manually can be complex but worth the time.

Service Principal Names

Microsoft defines a Service Principal Name (SPN) as, “a unique identifier of a service instance”. Kerberos authentication uses SPNs to associate a service instance with a service logon account.

SPNs can be applied to accounts and are common to find in an Active Directory environment. The reason we want to check for their presence is to discover if there are any accounts that would be good targets for Kerberoasting. We can run a quick query to see if any accounts have SPNs applied to them as shown below.

dsquery * -filter "(servicePrincipalName=*)" -attr name servicePrincipalName

NOTE: This query may be detected by identity protection products as enumeration for Kerberoasting.

In the above example, we are querying for any account that has an SPN applied to it. In the results, we can see there are four accounts. The first one is the computer account belonging to the Domain Controller, which has several SPNs applied. This account, along with the PFRY-WIN-10 computer account would not be good targets for Kerberoasting. This is because computer accounts typically have long randomized passwords set and are difficult to break. Similarly, the krbtgt account would not be a good target for Kerberoasting; if the krbtgt password is easy to crack, the domain is in a very bad position already. The third account in the returned list is a user account, which could potentially be a good candidate for Kerberoasting.

This is not all the information you would need to determine if Kerberoasting is a viable option, but it is information from a quick query that could inform you on potential attack paths. As we have seen with other queries, we can narrow down our results to user accounts only to save a bit of time.

User Account Control

The userAccountControl attribute is a number set depending on the user account setting. These are not as straightforward as some of the other attributes we have discussed so far and the available Microsoft documentation is incomplete on what the numbers indicate. Fortunately other resources contains a more complete list.

Since the domain we are working in here is small, we can list out this attribute for all users as shown below.

dsquery * -filter "(userAccountControl=*)" -attr name userAccountControl

The first value of 512 indicates a NORMAL_ACCOUNT which applied to HFarnsworth and Hermes Conrad. This can be a bit misleading as we know from previous queries that HFarnsworth is a Domain Administrator. So, what does this mean then? If we look at it from the Administrator perspective, we can see this is related to the “Account options” settings as shown below.

What the 512 value indicates is that the user accounts do not have any of the properties enabled. It does not indicate the users’ permissions or privileges in the environment.

The next value is the 514, which means the account is disabled. In addition to the krbtgt account having this value, we can see that the Scruffy Service account is also disabled. This is something we would want to note if the Scruffy Service account were one we wished to target. Additionally, you can use the userAccountControl to filter out disabled accounts like the query below.

dsquery * -filter "(&(objectClass=user)(!(userAccountControl=514)))" -attr name userAccountControl

The next item we will look at is the 66048 value, which indicates a user account whose password does not expire. This could be a good account to go after because it could indicate that the account has an old password, which may be easier to obtain or crack. In the example below, we are printing out which users have a password set to not expire, as well as the pwdLastSet attribute which can help target accounts with old passwords.

dsquery * -filter "(userAccountControl=66048)" -attr name userAccountControl pwdLastSet

There are several more interesting values, but I would suggest reading the sources linked for additional information. The value is shown in decimal, but it is calculated in hexadecimal and is cumulative with an addition calculation. For example, most user accounts are labeled as NORMAL_ACCOUNT, which has a decimal value of 512 and a hexadecimal value of 0x0200. If the password is stored using reversible encryption, it will be assigned a user account control value of 128 in decimal and 0x0080 in hexadecimal. The account setting is displayed as shown in the image below within Active Directory Users & Computers (ADUC).

So if a normal user account is set to store the password with reversible encryption and no other options set, the value for that account would be 640 (512 + 128) in decimal, and 0x0280 (0x0200 + 0x0080) in hexadecimal. This makes querying for a specific user account control setting easy because the value will be unique based on the calculation of the settings for the user. We can query for a user account control value and it will pull all users who have that setting. However, if we were to just query with userAccountControl and the value, we would only get the users with that exact calculated value. In the image below, the query is looking for normal user accounts, but it is only pulling one account.

dsquery * -filter "(userAccountControl=512)" -attr name userAccountControl

Since that is not at all helpful, we have to add a bit filter for bit-wise comparison by specifying the BitFilterRule ID. There is an AND and OR filter:

  • LDAP_MATCHING_RULE_BIT_AND 1.2.840.113556.1.4.803
  • LDAP_MATCHING_RULE_BIT_OR 1.2.840.113556.1.4.804

The way this is added to the LDAP filter is in the following format:

<Attribute name>:<BitFilterRule-ID>:=<decimal comparative value>

With this filter, we can pull all users with a specific setting as well as other settings calculated in the userAccountControl value. As shown below, either filter will work for this particular query, but depending on what you are searching for, you should choose the appropriate filter.

dsquery * -filter "(userAccountControl:1.2.840.113556.1.4.803:=512)" -attr name userAccountControl

dsquery * -filter "(userAccountControl:1.2.840.113556.1.4.804:=512)" -attr name userAccountControl

With the BitFilterRule, you can query for other values stored in a hexadecimal value, such as grouptype.

Passwords in LDAP Attributes

Although most organizations make efforts to secure passwords, it is possible that passwords or password hashes are stored in LDAP attributes. The most common way I have seen this occur is when an organization adds software to the environment that can use AD for authentication. Sometimes this software will update the schema to add additional attributes in AD which store passwords or hashes. To find this, you can search if these fields exist and are populated in an environment with the following filter:

"(|(UserPassword=*)(unicodePwd=*)(UnixUserPassword=*) (msSFU30Password=*)(orclCommonAttribute=*)(defender-tokenData=*)(ms-Mcs-AdmPwd=*))"

This filter includes common attributes which store credentials in AD. These are the attributes this filter looks at:

Another area where I have found passwords stored is in the description for accounts, so it is a good idea to check there as well.

Organizational Units

Organizational units (OUs) are logical groups for objects in AD. OUs differ from containers because they allow policies in the form of Group Policy Objects (GPOs) to be applied to them whereas containers do not. OUs can be created and organized at administrators’ discretion though, by default, one OU is automatically created for Domain Controllers when a domain is created. The OUs can be hierarchical, where one OU is added as a member to another OU and can be nested. Many organizations will create the OU structure to reflect the organization’s business structure.

To get a quick list of the OUs in a domain, you can run the dsquery command for the object class “organizationalUnit” to get the OUs.

dsquery * -filter "(objectClass=organizationalUnit)"

This will give you the distinguished names of the OUs. In this domain, the Device OU is nested under the Domain Computers OU, which is reflected in the full name of the OU. If we are querying an object, the OU is reflected in the distinguished name of the object.

dsquery * -filter "(name=BROD-SELF)" -attr name distinguishedName

This will reflect where in the AD the structure object resides. If the object is not in any OUs, the distinguished name will reflect where in the container structure the object resides as shown below.

dsquery * -filter "(name=FS-CREW)" -attr name distinguishedName

The difference between these two is the computer object that is not in an OU would not have GPOs applied to it. If you were looking for objects to target, this could be an indication of a misconfiguration in an AD environment where an object was created in the wrong container or OU and does not have the same policies applied.

Searching for objects in an OU is not as straightforward as some other queries. OUs for an object make up the distinguished name, but this does not form a separate attribute stored in the object information. LDAP does not have a way for you to partially match a distinguished name easily and wildcards will not return results. Instead, you can specify the distinguished name as the start node for your query. This will specify the OU where you want the query to start searching for the objects specified in the LDAP filter.

dsquery * -filter "(objectCategory=computer)" -attr name distinguishedName

dsquery * "OU=Domain Computers,DC=PLANETEXPRESS,DC=LOCAL" -filter “(objectCategory=computer)” -attr name distinguishedName

dsquery * "OU=Devices,OU=Domain Computers,DC=PLANETEXPRESS,DC=LOCAL" -filter “(objectCategory=computer)” -attr name distinguishedName

In the first query, the search will encompass the entire domain. In the second query, we are specifying the start node which will begin searching in the "OU=Domain Computers,DC=PLANETEXPRESS,DC=LOCAL" for objects. In the third query, we are specifying the nested OU, "OU=Devices,OU=Domain Computers,DC=PLANETEXPRESS,DC=LOCAL", as where we want to start our search. As we can see, specifying the start node will give us more specific results depending on what OU we are starting our search in.

Lastly, if we wanted to see the objects in an OU, an alternate way we could view this information quickly is by providing the start name in our query and simply specify the OU as the start node.

dsquery * "OU=Domain Computers,DC=PLANETEXPRESS,DC=LOCAL"

Typically, when querying for OUs from an operational perspective, the goal is to correlate the objects with what group policies are applied to it or vice versa.

Domain Trusts

For this section, I will assume you are already familiar with the concepts and terms associated with domain trusts. If you are not, this resource from Microsoft can help to get you familiar with what you need to know. The important thing to know is that when a trust relationship is established between domains, the relationship is represented in AD as a trusted domain object. The easiest way to start looking at the trust relationships is by querying for that object type, as shown below:

dsquery * -filter "(objectCategory=trustedDomain)"

The information provided here is limited but it will give us a quick list of what relationships, if any, exist in a domain. This alone is not enough information to understand the trust relationship between the domains, so we will need to get additional information. If you are looking for a specific type of trust relationship, you can filter the trustDirection attribute in your LDAP filter to specify the type of relationship.

dsquery * -filter "(trustDirection=3)”

Since this attribute is unique to this object type, we can filter for just that attribute for a less complicated filter. In this example, the value of 3 means that it is a bidirectional trust relationship. For additional information, you can review the Microsoft documentation here. For quick reference, the following is the mapping of numbers to relationships:

  • 0 — trust relationship is disabled
  • 1 — trust relationship is inbound
  • 2 — trust relationship is outbound
  • 3 — trust relationship is bidirectional

Trust type is another attribute that can help us to understand trust relationships. The trust type, represented with the trustType attribute, will indicate the type of trust the current domain has with the foreign domain.

dsquery * -filter "(trustType=2)"

With this query, we are specifically looking for domains which are Windows domains and are running Windows AD. The type of domain is relevant when you are looking to cross domains and want to know what technology the other trusted domain is running. LDAP works with environments not running Windows AD, so LDAP queries and filters will often work as well. To read more about the trust types, Windows has provided this documentation. The quick meaning of the trust type values is as follows:

  • 1 — Windows domain not running AD
  • 2 — Windows domain running AD
  • 3 — non-Windows with Kerberos
  • 4 — not used
  • 5 — Entra ID (formerly Azure AD)

Trust partner is a mandatory attribute which holds the fully qualified domain name (FQDN) of the trusted domain. When you are enumerating the trust relationships, the FQDN is necessary for activities such as querying into the trusted domain or interacting with some resources in the other domain.

dsquery * -filter "(objectClass=trustedDomain)" -attr name trustPartner

Instead of searching by this attribute, this query will retrieve the trusted domain objects and list the name and trustPartner attributes. This is a simple attribute, however additional information can be found in the Microsoft documentation. Keep in mind that when you are querying, limiting your output can be very beneficial for getting exactly the information you need to work with.

The last part of the discussion of trust relationships is the trust attributes. This is another attribute which describes the trust relationship the current domain has with other trusted domains.

dsquery * -filter "(trustAttributes=8)"

In this example, the filter will return trust relationships which have a trustAttributes value of 8, which means the trust is established between forests. These trust attributes can help inform you on how you can interact with another domain due to the attribute value containing information on restrictions. There is further detail in the documentation from Microsoft on the trust attributes. The quick reference for these attributes is as follows:

  • 1 — Trust is not transitive
  • 2 — Only Windows 2000 and newer operating systems can use the trust
  • 4 — Domain is quarantined and subject to SID filtering
  • 8 — Cross forest trust between forests
  • 16 — Domain or forest is not part of the organization
  • 32 — Trusted domain is in the same forest
  • 64 — Trust is treated as an external trust for SID filtering
  • 128 — Set when trustType is TRUST_TYPE_MIT, which can use RC4 keys
  • 512 — Tickets under this trust are not trusted for delegation
  • 1024 — Cross-forest trust to a domain is treated as Privileged Identity Management (PIM) trust for the purposes of SID filtering
  • 2048 — Tickets under this trust are trusted for delegation

Foreign Security Principal

The foreign security principal is an object which originates from an external source. The easiest way to identify a foreign security principal is to query for the object class.

dsquery * -filter "(objectClass=foreignSecurityPrincipal)"

The first four items can be ignored or filtered out because they are standard in every domain. Unlike the other returned objects, the principal is not stored with an easily readable name but uses the object SID to represent the object. When retrieving further information on the object, we can see that it is still not entirely clear what the object is.

dsquery * -filter "(distinguishedName=CN=S-1–5–21–3542491776–619976232–3744802786–1605,CN=ForeignSecurityPrincipals,DC=PLANETEXPRESS,DC=LOCAL)" -attr *

Since the setup within this environment is simple, with only one other connected domain, the object is easy to find in the trusted domain by using the trust relationship that is established between the domains. Depending on the tool you are using, the flags will be different, but in dsquery the /domain flag will query another domain for information.

dsquery * -filter "(objectSid=S-1–5–21–3542491776–619976232–3744802786–1605)" /domain DOOP-HQ.LOCAL

Expanding the attributes will provide additional information about the object.

dsquery * -filter "(objectSid=S-1–5–21–3542491776–619976232–3744802786–1605)" /domain DOOP-HQ.LOCAL -attr *

With this, we can see the object is a group which references a user from the foreign domain. This information is helpful when understanding how trust relationships are used in an environment. These sorts of relationships can be potential paths for traversal in an environment when looking to move to a different domain.

Conclusion

That’s it for another round of LDAP filter discussions. The topics in this blog were chosen based on what I was not able to cover in the last blog and feedback I received from the first blog. Unfortunately, there again was not the space or time to explain everything, but hopefully this helps create a bit more understanding about manual LDAP querying.

Special thanks to Adam and Sarah for proofreading and editing!


Manual LDAP Querying: Part 2 was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.

The post Manual LDAP Querying: Part 2 appeared first on Security Boulevard.

ADCS Attack Paths in BloodHound — Part 2

1 May 2024 at 11:57

ADCS Attack Paths in BloodHound — Part 2

In Part 1 of this series, we explained how we incorporated Active Directory Certificate Services (ADCS) objects into BloodHound and demonstrated how to effectively use BloodHound to identify attack paths including the ESC1 abuse technique.

In this blog post, we will continue to explore more of the new edges we have introduced with ADCS support in BloodHound. More specifically, we will cover how we have incorporated the Golden Certificate and the ESC3 abuse technique.

I have written this blog post on behalf of the BloodHound Enterprise team at SpecterOps, which has designed and implemented the BloodHound edges described in this blog post. Thanks to everyone on the team who helped out with this effort!

Hosts and Golden Certificate

The computer hosting a certificate authority (CA) service holds the private key of its CA certificate. The key must be there for the CA to sign and issue certificates. This makes CA hosts a very lucrative target. As Will Schroeder and Lee Chagolla-Christensen described under DPERSIST1 in the ADCS whitepaper Certified Pre-Owned, it is possible to craft “golden certificates” with the private key of the CA certificate, which then allows you to authenticate as anyone just as ESC1.

The AD enterprise CA object holds the DNS name of its CA host in its dNSHostName attribute. This enables us to look up the corresponding AD computer object. To represent the relationship between the AD computer object and the enterprise CA object in BloodHound, we create a non-traversable edge named HostsCAService, going from the Computer node to the EnterpriseCA node.

For an attacker to craft a golden certificate that works for domain authentication, the enterprise CA’s certificate must chain up to a trusted root CA for the domain, and the NTAuth store must include the enterprise CA certificate, just as with ESC1. If these conditions are met, we create a traversable GoldenCert edge from the CA Computer node to the domain:

The GoldenCert edge makes it easy to identify attack paths leading to a domain compromise through a CA host.

Many organizations do not protect enterprise CA hosts as well as they should. It is a common misunderstanding that only root CAs are Tier Zero, and not issuing CAs and intermediate CAs. Both issuing CAs and intermediate CAs are enterprise CAs, and will by default meet the requirements for the GoldenCert edge. We strongly recommend treating all CA hosts as Tier Zero.

There are exceptions to the statement in the above meme; for example, hardware protection on the CA host may prevent you from obtaining the CA private key. However, it is still possible to compromise the environment most likely, as an enterprise CA host can publish certificate templates, approve certificate requests the CA has denied, and more.

We will dive further into the edges in the above screenshot in a future blog post about ESC5 and ESC7.

There are even scenarios where an attacker can abuse a compromised CA host not trusted for NT authentication. An attacker may compromise users configured with an explicit certificate mapping of the type X509IssuerSubject, X509IssuerSerialNumber, X509SKI, or X509SHA1PublicKey as Hans-Joachim Knobloch called out and described in this blog post: Kleines Nilpferd trampelt über Microsofts PKI-Webdienste. The attacker can also compromise any group set up with Authentication Mechanism Assurance (AMA), as Carl Sörqvist explains in this blog post: Forest Compromise Through AMA Abuse.

ESC3

ESC3 is similar to ESC1 in the sense that you as an attacker enroll a certificate as a targeted principal of your choice, which you then use to perform domain authentication. In ESC3, we abuse the ADCS concept of enrollment agents. Let us dive into the requirements.

Enrollment Agent Templates

An enrollment agent can enroll certificates on behalf of other principals. The most frequent use case for the enrollment agent concept is for an administrator who needs to issue smart cards to employees of the organization. The administrator will obtain an enrollment agent certificate and use that to enroll certificates on behalf of employees who need a smart card. This is a more secure solution than using an ESC1-type certificate template, as the enrollment agent setup enables you to restrict the targeted certificate templates and the targeted principals, as we will explore later in this blog post.

To become an enrollment agent, you need an enrollment agent certificate containing the extended key usage (EKU): Certificate Request Agent (1.3.6.1.4.1.311.20.2.1). Such a certificate allows you to enroll on behalf of other principals in all certificate templates of schema version 1. Additionally, targeted templates of schema version 1 also allow the enroll-on-behalf-of functionality if you present a certificate with the Any Purpose EKU or no EKUs (ESC2 certificate). As explained in the Part 1 blog post, you can view the effective EKUs of certificate templates on the CertTemplate node entity panel in BloodHound:

If the targeted certificate template is of schema version 2 or above, then the targeted template must contain the Certificate Request Agent EKU in its msPKI-RA-Application-Policies attribute to allow enroll-on-behalf-of functionality. You can check this requirement under Issuance Requirements in the Windows built-in Certificate Templates Console (certtmpl.msc):

Alternatively, you can check the Application Policies property in BloodHound:

At last, the enrollment agent certificate needs to chain up to a trusted root CA for the environment of the targeted certificate template.

To make it easy to find enrollment agent certificate templates and find the certificate templates that will accept the enrollment agent certificate, we have implemented a new non-traversable edge named EnrollOnBehalfOf to represent exactly that relationship:

To summarize, we create an EnrollOnBehalfOf edge between an enrollment agent certificate template and a targeted template if the following requirements are met.

If the targeted template is of schema version 1:

  • The enrollment agent template has one of the EKUs:
    - Certificate Request Agent
    - Any Purpose
    - Null (No EKUs)

If the targeted template is of schema version 2 or above:

  • The enrollment agent template has the Certificate Request Agent EKU
  • The targeted template contains the Certificate Request Agent EKU in its msPKI-RA-Application-Policies attribute.

Additionally, the enrollment agent certificate must chain up to a trusted root CA for the environment of the targeted certificate template.

Requirements for Enrollment and Domain Authentication

To use (or abuse) an enrollment agent certificate template, you need enrollment rights on the enrollment agent certificate template, the targeted template, and an enterprise CA with the templates published. Note that it does not have to be the same enterprise CA that has both templates published. Both the enterprise CA for the enrollment agent template and the enterprise CA for the targeted template must chain up to a trusted root CA for the domain, and the NTAuth store must include the enterprise CA certificate.

Issuance requirements, manager approval and authorized signatures required, can prevent enrollment on a certificate template. Both the enrollment agent certificate template and the targeted template must have manager approval disabled. The enrollment agent template must also have no authorized signatures required but the targeted template will have this set to one, as it requires the Certificate Request Agent EKU, unless it is of schema version 1 which does not support authorized signatures.

At last, the targeted template must enable domain authentication for the attacker to log in as the targeted principal.

To summarize, we add the following requirements for the ADCSESC3 edge:

  • The principal has enrollment rights (potentially through group membership) on:
    - The enrollment agent template
    - The targeted template
    - One or more enterprise CAs where the templates are published
  • The certificate chain of the enterprise CA with the enrollment agent template published is trusted
  • The certificate chain of the enterprise CA with the targeted template published is trusted
  • The enterprise CA of the targeted template is trusted for NT authentication
  • The enrollment agent template has manager approval disabled
  • The targeted template has manager approval disabled
  • The enrollment agent template has no authorized signatures required
  • The targeted template enables domain authentication

The Part 1 blog post covers all of the above requirements in detail.

Subject Name and Subject Alternative Name Requirements

A principal must meet a certificate template’s Subject Name and Subject Alternative Name (SAN) requirements to enroll in it. The certificate template has these requirements defined on the Subject Name tab of the Certificate Templates Console:

I documented my research of these requirements in the Certificate Template Flags and Certificate Fields section of the ADCS ESC14 blog post. Here are the key takeaways in terms of flags that prevent principals from enrolling:

  • DNS required (CT_FLAG_SUBJECT_ALT_REQUIRE_DNS or CT_FLAG_SUBJECT_ALT_REQUIRE_DOMAIN_DNS): Only principals with their dNSHostName attribute set can enroll
    The AD user class does not include the dNSHostName attribute, so users cannot enroll in certificate templates requiring dNSHostName. Computers will get their dNSHostName attribute set when you domain-join a computer, but the attribute is null if you simply create a computer object in AD. Computers have validated write to their dNSHostName attribute meaning they can add a DNS name matching their computer name.
  • Email required (CT_FLAG_SUBJECT_ALT_REQUIRE_EMAIL or CT_FLAG_SUBJECT_REQUIRE_EMAIL): Only principals with their mail attribute set can enroll unless the template is of schema version 1
    Users and computers do not have their mail attribute set by default, and they cannot write to the attribute themselves. It is common to see users with the mail attribute set, but rare for computers.

When performing the enroll-on-behalf-of enrollment in a given target certificate template, it is then the target principal’s attribute that goes into the certificate. Therefore, it is the target principal that must meet the target template’s requirements for DNS and email and not the enrollment agent principal.

You can check what the certificate requires for Subject Name and SAN in the CertTemplate entity panel:

In case you want to know what an entity panel field corresponds to in AD, or what the BloodHound database name is (for the Cypher-ninjas), then you can look up the node documentation at https://support.bloodhoundenterprise.io:

We want to avoid creating false positive BloodHound edges that make you feel like Bad Luck Brian here:

If a user meets all the requirements for an ESC3 abuse, but the enrollment agent certificate template requires DNS, then we can say with certainty that the user cannot execute the abuse. In other scenarios, it depends on your level of control over the principal as an attacker. For example, a template that requires the mail attribute set prevents the abuse for principals without mail, but an attacker with write access to the mail attribute of the principal can easily circumvent that.

To summarize, we add the following ADCSESC3 requirement:

  • If the attacker principal is a user:
    - The enrollment agent certificate template does not require DNS

Enrollment Agent Restrictions

You can configure super granular enrollment agent restrictions per each enterprise CA. You can specify exactly what principals the CA should allow enrolling as enrollment agents in what certificate templates and on behalf of which targeted principals:

This is super powerful from a defensive perspective, but challenging to model with a graph as each rule potentially involves more than two nodes. What we have done, though, is create a non-traversable edge named DelegatedEnrollmentAgent from the enrollment agent principals to the certificate templates specified in the restrictions, if it is an allow-rule.

The CA host stores the enrollment agent restrictions in registry. You can see whether SharpHound collected the enrollment agent restrictions and whether the CA has any in the EnterpriseCA node entity panel:

We add a final requirement for the ADCSESC3 edge:

  • If the enterprise CA of the targeted certificate template has enrollment agent restrictions:
    - The principal has a DelegatedEnrollmentAgent edge to the targeted certificate template (potentially through group membership)

The ADCSESC3 Edge

For principals that meet all the requirements above and have the permissions required to perform an ESC3 abuse, BloodHound creates a traversable ADCSESC3 edge to the forest root domain, similar to the ADCSESC1 edge. So instead of checking all the requirements manually, you can easily identify attack paths that include the ESC3 abuse:

As with all other edges, you can click on it to view the related entity panel and learn more about the edge; including how to abuse it:

Clicking on “Composition” in the edge entity panel reveals the composition graph with the nodes and edges the ADCSESC3 edge is based on:

The graph shows you how the principal meets the requirements for the ESC3 abuse. The graph in the above screenshot is a simple example that only contains a single EnterpriseCA node and two CertTemplates. You may encounter graphs with many more nodes if the principal meets the requirement through several certificate templates and enterprise CAs.

The graph may also include a DelegatedEnrollmentAgent edge:

If you see one of these DelegatedEnrollmentAgent edges in the composition graph, check the scope of targeted principals in the enrollment agent restrictions and confirm that there is no deny rule overruling the permission.

No ESC2 in BloodHound?

ESC2 is where you enroll a certificate with the Any Purpose EKU or no EKUs (a.k.a., sub-CA certificate). The Any Purpose EKU means you can use the certificate for any purpose, but it does not enable impersonation on its own. A sub-CA certificate enables you to create certificates of any kind including certificates as other principals. However, you cannot perform domain authentication using these certificates, as the NTAuth store does not include the sub-CA certificate automatically. That leaves us with no end node we can draw a potential ADCSESC2 edge to.

ESC2 certificates are still powerful, though, and may enable an attacker to perform an attack outside of the scope of BloodHound. You can use this pre-built Cypher query to find principals with enrollment rights on ESC2 certificate templates:

We have also added a handful of other ADCS queries that you might find useful. Check them out, and feel free to submit a pull request if you feel like something is missing.

What is Next

We have now covered ESC1, Golden Certificate, and ESC3 with this blog post series. Stay tuned for future posts, as we will dive further into more advanced ADCS escalations and how you can identify them using BloodHound.

We are very eager to get your feedback. Please join us in the BloodHound Slack or report any issues on the BloodHound GitHub repo.


ADCS Attack Paths in BloodHound — Part 2 was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.

The post ADCS Attack Paths in BloodHound — Part 2 appeared first on Security Boulevard.

The Role of Threat Intelligence in Financial Data Protection

By: Enzoic
25 April 2024 at 13:03

As the financial industry increasingly adopts digital processes, it faces a growing array of cybersecurity threats. Cybercriminals target sensitive customer data held by retail banks and credit unions, exploiting vulnerabilities in digital systems to steal valuable information such as personally identifiable information (PII), account details, and payment card data. These attacks, which include phishing, malware, […]

The post The Role of Threat Intelligence in Financial Data Protection appeared first on Enzoic.

The post The Role of Threat Intelligence in Financial Data Protection appeared first on Security Boulevard.

❌
❌