
Domain and forest trusts are a well-known research topic. Rather than revisiting all of its aspects, the present article focuses on one-way trusts: the account used for maintaining the trust between domains can be extracted with a new tool, tdo_dump.py from the trusting domain and used to authenticate on the trusted domain. Thus, trusted domain objects can be helpful in performing lateral movement across security boundaries within Windows environments.

Introduction
Microsoft defines a one-way trust as the following (emphasis ours):
“A one-way trust is a unidirectional authentication path created between two domains (trust flows in one direction, and access flows in the other). This means that in a one-way trust between a trusted domain and a trusting domain, users or computers in the trusted domain can access resources in the trusting domain. However, users in the trusting domain cannot access resources in the trusted domain. Some one-way trusts can be either nontransitive or transitive, depending on the type of trust being created.”
The concept is straightforward and can be summed up in a diagram:

Two Windows domains, part of two distinct forests, are bound with a one-way trust: offsec.lol trusts admin.yeah. So admin.yeah accounts can authenticate to offsec.lol, but not the other way around… allegedly.
To maintain a trust between those forests, a domain account is automatically created on the trusted forest during the trust creation. The samaccounttype of this account is TRUST_ACCOUNT and its useraccountcontrol is (by default) PASSWD_NOTREQD and INTERDOMAIN_TRUST_ACCOUNT.
Obviously, the secrets for this account can be dumped by an attacker with Domain Admins privileges on the trusted domain.
However, on the trusting domain, no account is created. This is the expected behavior: the trusting domain does not need to verify identities on the trusted domain because it (trusted) doesn’t trust it (trusting) back. That said, the trusting domain needs to store the password of the account created on the trusted domain. Thus, it is possible for an attacker with Domain admins privileges on the trusting domain to perform lateral movement on the trusted domain. This has already been documented in at least two blogposts: a trusted domain object takeover allows attackers that control the trusting domain to gain Domain Users access on the trusted domain.


Trusted domain object
According to the documentation, the password is stored in cleartext within a LSAPR_AUTH_INFORMATION structure in a trusted domain object (TDO). It also can be stored as a raw RC4HMAC key but only if the trust relationship is set between a Windows domain and a non-Windows, RFC4120-compliant Kerberos distribution domain, which is beyond the scope of this blog post.
There are already tools capable of dumping trusted domain objects, such as mimikatz or ntdissector.

On the left side, the TDO is dumped on offsec.lol on the right side on admin.yeah. On the trusting domain side, the IN part of the TDO is empty and on the trusted side the OUT part is also empty, confirming that the trust is one-way. You can also see that the trust password history is the same as the current password: it means the trust was created less than 30 days ago.
The main problems of those tools are: they can’t be used remotely, and they only display the inter-domain trust keys, not the Kerberos keys. Indeed, to actually use the account, it is the Kerberos keys of the TRUST_ACCOUNT (OFFSEC$) that are needed.
The password within the TDO on offsec.lol is the same as the password of OFFSEC$ on admin.yeah. Thus, an attacker that has compromised the trusting domain can now have valid credentials on the trusted domain. The unidirectional “direction of access” is in fact bidirectional (at least for one account).

The tool
In most blogposts about trusts, mimikatz is used to dump the trust domain object. We decided to create a python script based on impacket to implement this attack: tdo_dump.py.
To keep it simple and easy to debug, we choose to reduce the actions performed by our script: only DRSBind, DRSGetNCChanges and DRSUnbind are called. Because DRSGetNCChanges can be a complex function call so for our script we kept it simple as well. Thus, the GUID of the TDO as well as the GUID of the nTDSDSA object of the targeted domain controller must be provided to the script. The nTDSDSA object is an object that represents the replication agent of the domain controller.
Those two GUIDs can be retrieved using your favorite AD object explorer.
Once the object is retrieved, the script parses it according to Microsoft’s documentation.
In a typical “Windows domain” case, the password within the structure is stored in cleartext, and various secrets are derived from it. To derive the Kerberos inter domain trust keys, the salt is computed with the following elements:
TRUSTED_DOMAIN_FQDN + krbtgt + TRUSTING_DOMAIN_FQDN
in our case
ADMIN.YEAHkrbtgtOFFSEC.LOL
The salt kerberos key for the TRUST_ACCOUNT is computed like this:
TRUSTED_DOMAIN_FQDN + krbtgt + TRUST_ACCOUNT_SAMACCOUNTNAME_WITHOUT_$
in our case
ADMIN.YEAHkrbtgtOFFSEC
Bear in mind that a TDO account cannot use NTLM authentication, only Kerberos. Consequently, once the attacker has the kerberos keys for the TRUST_ACCOUNT, they can authenticate to the trusted domain. In this scenario, the inter realm keys are not particularly useful because the attacker already controls the trusting domain.
The tool is now available on GitHub.

Consequences
The main consequence, as stated above, is that the compromise of the trusting forest gives an authenticated access on the trusted forest. This breaks the typical expectation that a one-way trust only allows traversing the forest security boundary in one direction. This is especially true in the typical “administration forest” use case of one-way trusts.
Most of the usual AD attacks – that require a domain account – can be performed on the trusted domain/forest using the TDO account, including, but not limited to:
- LDAP recon
- AD CS
- Computer account creation
- Kerberoasting

Shout out
tdo_dump.py is heavily based on:
- previous (private) work by @SAERXCIT.
- previous work and research by Dirk-jan Mollema.
- the impacket project and the work of all its contributors.