A Guide to Attacking Domain Trusts

WTF Are Domain Trusts?

At a high level, a domain trust establishes the ability for users in one domain to authenticate to resources or act as a security principal in another domain. Microsoft has a lot of information out there about domain trusts, as well as “Security Considerations for Trusts”, and it can sometimes get a bit confusing. As Microsoft describes, “Most organizations that have more than one domain have a legitimate need for users to access shared resources located in a different domain“, and trusts allow organizations with multiple domains to grant users in separate domains access to shared resources. Domain forests are collections of domain containers that trust each other. Forests themselves may also have trusts between them. Microsoft has excellent post about how domain and forest trusts work. If you’re not familiar with this topic, I recommend that you check it out.

  • Parent/Child — part of the same forest — a child domain retains an implicit two-way transitive trust with its parent. This is probably the most common type of trust that you’ll encounter.
  • Cross-link — aka a “shortcut trust” between child domains to improve referral times. Normally referrals in a complex forest have to filter up to the forest root and then back down to the target domain, so for a geographically spread out scenario, cross-links can make sense to cut down on authentication times.
  • External — an implicitly non-transitive trust created between disparate domains. “External trusts provide access to resources in a domain outside of the forest that is not already joined by a forest trust.” External trusts enforce SID filtering, a security protection covered later in this post.
  • Tree-root — an implicit two-way transitive trust between the forest root domain and the new tree root you’re adding. I haven’t encountered tree-root trusts too often, but from the Microsoft documentation, they’re created when you when you create a new domain tree in a forest. These are intra-forest trusts, and they preserve two-way transitivity while allowing the tree to have a separate domain name (instead of child.parent.com).
  • Forest — a transitive trust between one forest root domain and another forest root domain. Forest trusts also enforce SID filtering.
  • MIT — a trust with a non-Windows RFC4120-compliant Kerberos domain. I hope to dive more into MIT trusts in the future.
https://technet.microsoft.com/en-us/library/cc759554(v=ws.10).aspx

Why Care?

But really, why care?

A Trust Attack Strategy

Before we get into the technical details of how to enumerate and abuse trusts, I wanted to go over the high level strategy I use when auditing trust relationships. When I talk about a “trust attack strategy” what I mean is a way to laterally move from the domain in which your access currently resides into another domain you’re targeting.

OK, How Do I Enumerate Trusts?

OK Will, you’ve piqued my interest. How do I go about figuring out what trust relationships exist in my environment?

.NET Methods

.NET provides us with some nice method wrappers that can enumerate a good chunk of domain and forest trust information. This was the first method that PowerView implemented, before branching into Win32 API and LDAP methods.

Win32API

You can also enumerate domain trusts through the DsEnumerateDomainTrusts() Win32 API call which returns a DS_DOMAIN_TRUSTS structure. While the information is a bit more complex than the .NET methods, it returns the SID and GUID of the target domain, as well as some useful flags and attributes. The flags are documented here and will tell you the trust direction, whether the trust is within the same forest, etc. The attributes are documented here under the TrustAttributes specification, and include things like WITHIN_FOREST, NON_TRANSITIVE, FILTER_SIDS, and more. FILTER_SIDS is the equivalent of QUARANTINED_DOMAIN if you ever see that nomenclature.

LDAP

Domain trusts are stored in Active Directory as “trusted domain objects” with an objectClass of trustedDomain. This means you can use whatever LDAP querying method you would like to find out information about any domain trusts that are present by using the LDAP filter (objectClass=trustedDomain).

  • DOWNLEVEL (0x00000001) — a trusted Windows domain that IS NOT running Active Directory. This is output as WINDOWS_NON_ACTIVE_DIRECTORY in PowerView for those not as familiar with the terminology.
  • UPLEVEL (0x00000002) — a trusted Windows domain that IS running Active Directory.This is output as WINDOWS_ACTIVE_DIRECTORY in PowerView for those not as familiar with the terminology.
  • MIT (0x00000003) — a trusted domain that is running a non-Windows (*nix), RFC4120-compliant Kerberos distribution. This is labeled as MIT due to, well, MIT publishing RFC4120.
  • NON_TRANSITIVE (0x00000001) — the trust cannot be used transitively. That is, if DomainA trusts DomainB and DomainB trusts DomainC, then DomainA does not automatically trust DomainC. Also, if a trust is non-transitive, then you will not be able to query any Active Directory information from trusts up the chain from the non-transitive point. External trusts are implicitly non-transitive.
  • UPLEVEL_ONLY (0x00000002) — only Windows 2000 operating system and newer clients can use the trust.
  • QUARANTINED_DOMAIN (0x00000004) — SID filtering is enabled (more on this later). Output as FILTER_SIDS with PowerView for simplicity.
  • FOREST_TRANSITIVE (0x00000008) — cross-forest trust between the root of two domain forests running at least domain functional level 2003 or above.
  • CROSS_ORGANIZATION (0x00000010) — the trust is to a domain or forest that is not part of the organization, which adds the OTHER_ORGANIZATION SID. This is a bit of a weird one. I don’t remember encountering this flag in the field, but according to this post it means that the selective authentication security protection is enabled. For more information, check out this MSDN doc.
  • WITHIN_FOREST (0x00000020) — the trusted domain is within the same forest, meaning a parent->child or cross-link relationship
  • TREAT_AS_EXTERNAL (0x00000040) — the trust is to be treated as external for trust boundary purposes. According to the documentation, “If this bit is set, then a cross-forest trust to a domain is to be treated as an external trust for the purposes of SID Filtering. Cross-forest trusts are more stringently filtered than external trusts. This attribute relaxes those cross-forest trusts to be equivalent to external trusts.” This sounds enticing, and I’m not 100% sure on the security implications of this statement ¯\_(ツ)_/¯ but I will update this post if anything new surfaces.
  • USES_RC4_ENCRYPTION (0x00000080) — if the TrustType is MIT, specifies that the trust that supports RC4 keys.
  • USES_AES_KEYS (0x00000100) — not listed in the linked Microsoft documentation, but according to some documentation I’ve been able to find online, it specifies that AES keys are used to encrypt KRB TGTs.
  • CROSS_ORGANIZATION_NO_TGT_DELEGATION (0x00000200) — “If this bit is set, tickets granted under this trust MUST NOT be trusted for delegation.” This is described more in [MS-KILE] 3.3.5.7.5 (Cross-Domain Trust and Referrals.)
  • PIM_TRUST (0x00000400) — “If this bit and the TATE (treat as external) bit are set, then a cross-forest trust to a domain is to be treated as Privileged Identity Management trust for the purposes of SID Filtering.” According to [MS-PAC] 4.1.2.2 (SID Filtering and Claims Transformation), “A domain can be externally managed by a domain that is outside the forest. The trusting domain allows SIDs that are local to its forest to come over a PrivilegedIdentityManagement trust.” While I have not seen this in the field, and it’s only supported by domain functional level 2012R2 and above, it also warrants further investigation :)

Data Enumeration Across Trusts With PowerView

Last year I described my ground-up rewrite of PowerView. One of the changes mentioned was that now, any Get-Domain* function uses LDAP enumeration, meaning that we can pull said information from a domain that trusts us. This is done with the -Domain <domain.fqdn> parameter:

Mapping Domain Trusts

There are few ways I know of to map the “mesh” of one or more trusts that exist in your environment. The first is through the global catalog. I talked about this a bit in my “A Pentester’s Guide to Group Scoping” post, but I’ll reiterate some of that information here.

Visualizing Domain Trusts

Data is one thing, visualizations are another. A few years ago, one of my former workmates, Justin Warner, saw all this raw data and build a tool called DomainTrustExplorer that could perform some nodal analysis and visualization with PowerView’s mapped trust data.

Foreign Relationship Enumeration

Now that we’ve mapped out all domain trusts reachable from the machine we’re querying from, the next step in the attack planning phase hits few branches, depending on the specific types of the trusts we’ve encountered. These next steps need to be executed for the hop from each each domain to another in the attack path.

  • They can be added to local groups on individual machines, i.e. the local “Administrators” group on a server.
  • They can be added to groups in the foreign domain. There are some caveats depending on trust type and group scope, described shortly.
  • They can be added as principals in an access control list, most interesting for us as principals in ACEs in a DACL. For more background on ACLs/DACLs/ACEs, check out the “An ACE Up The Sleeve” whitepaper.

Case 1: Local Group Membership

This involves enumerating the local memberships of one or more systems through remote SAM (SAMR) or through GPO correlation. I won’t cover this case heavily here, but will note that we have had success in the past with targeted SAMR enumeration of high value servers or domain controllers for trust-hopping. The PowerView function to do this manually is Get-NetLocalGroupMember <server>, and BloodHound will do this all automatically for you.

Case 2: Foreign Group Membership

The group membership case gets a bit tricky. The member property of an Active Directory group and the memberOf property of a user/group object have a special type of relationship called linked attributes. I covered this in more depth in a previous post, but with linked attributes, Active Directory calculates the value of a given attribute, referred to as the back link (e.g. memberOf with users/groups) from the value of another attribute, referred to as the forward link (e.g. member with a group). The gist is that group membership is ultimately preserved within the target group itself in the member property, and this all gets a bit complicated over trusts. Hopefully this will make more sense shortly. Whether or not the memberOf property saved with a user/group object reflects their foreign group memberships depends on the nature of the trust and scoping of the foreign group they’re a member in.

  • Domain Local Groups can have intra-forest cross-domain users (users in the same forest as the group) added as members, as well as inter-forest cross-domain users (foreign security principals.)
  • Global Groups can not have any cross-domain memberships, even within the same forest. So for our purposes we can ignore these.
  • Universal Groups can have any user in the forest as a member, but “foreign security principals” (i.e. users from forest/external trusts) can not be a part of universal groups.

Case 3: Foreign ACL Principals

Luckily most of the ntSecurityDescriptor property of Active Directory objects is (1) accessible to any domain authenticated user, and (2) replicated in the global catalog. This means that if from your current domain context, you can query the DACLs for all objects in a trusting domain, and filter any ACE entries where a foreign security principal has the given right on the object you’re enumerating.

Operational Guidance

Note: I’ll also walk over all steps needed in the Case Study section later in the post in case parts of this don’t make sense.

The Trustpocalypse — SID Hopping Up Intra-Forest Trusts

This is one of my favorite things I’ve learned about in the last few years in security. Just as most people remember the first time they saw Mimikatz extract a plaintext password out of memory, the memory of when I realized what this attack entailed is seared into my mind.

A Case Study

So, consider again the sample trust diagram:

Sidenote: Forging Inter-Realm Trust Tickets

It is possible to forge inter-realm trust tickets to exploit trust relationships. As Sean covered this extremely well in his “It’s All About Trust” post, I’ll refer you to his documentation for more operational details, and will just cover the implications of this technique and how it fits into our trust attack strategy.

Another Sidenote: Kerberoasting Across Domain Trusts

We love Kerberoasting. Introduced by Tim Medin in 2014, we ‘roast on a ton of our engagements. And if we have a domain that trusts us, we can roast across these trust boundaries, with one minor tweak in some situations.

Epilogue: SID Filtering

So we previously talked about how/why the forest is the trust boundary in Active Directory, not the domain. A big part of this is the security protection I’ve alluded to several times previously called SID Filtering. The best reference for SID filtering is the [MS-PAC] “Privilege Attribute Certificate Data Structure” documentation, specifically section 4.1.2.2 “SID Filtering and Claims Transformation.” I will do my best to explain a few salient points.

Wrapup

Trusts are not a simple topic. Most pentesters (and many sysadmins!) do not properly understand trusts and the risk exposed by various trust misconfigurations. Unfortunately for us, some bad guys do, and trusts have been abused since nearly the beginning of Active Directory to exploit access in one domain in order to pivot into another.

--

--

Researcher @SpecterOps . Coding towards chaotic good while living on the decision boundary.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Will Schroeder

Will Schroeder

Researcher @SpecterOps . Coding towards chaotic good while living on the decision boundary.