ADTRUST-010: Trust Key Age and Rotation
- Plataforma
- Active Directory
- Categoría
- AD Trust Relationships
- Severidad
- High
- Pilar de Zero Trust
- Identity (peso 3)
- Fixtures de referencia
- 3
- Cobertura de ramas
- Observada: los fixtures prueban los veredictos que ejercitan
- Procedencia
- baseline
Qué comprueba
For every trustedDomain object in CN=System,<domain DN> the check reads: - pwdLastSet (FILETIME of the last successful inter-realm key change; converted to a UTC timestamp and compared against now()) - trustAuthOutgoing and trustAuthIncoming (encoded LSAPR_AUTH_INFORMATION_INTERNAL blobs containing the current key, the previous key, and the kvno for each direction) - trustAttributes (to determine whether the trust is intra-forest, where rotation is automatic between writable DCs, or external/forest, where rotation requires Netlogon on both sides to be healthy) - trustDirection (1 inbound, 2 outbound, 3 bidirectional; inbound trusts are rotated by the trusting domain, outbound by the trusted partner, so a stale outbound key implies the partner has stopped rotating) - whenChanged on the trustedDomain object (a secondary indicator: if pwdLastSet is fresh but whenChanged is stale, only the kvno was bumped without the rest of the trust metadata being touched) The check then queries every reachable domain controller for the Netlogon policy that gates rotation: - HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange (DWORD; if 1, the DC will not initiate any machine or trust password change) - HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge (DWORD in days; if set higher than 30 the rotation window stretches accordingly, and a value above 60 is a hard flag) - HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\RefusePasswordChange (DWORD; if 1, the DC will not accept inbound password change requests, which silently breaks rotation on the partner side) The corresponding Group Policy settings under Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options ("Domain controller: Refuse machine account password changes" and "Domain member: Disable machine account password changes" and "Domain member: Maximum machine account password age") are also resolved via gpresult /R against the Domain Controllers OU so that an inherited policy override is surfaced even when the local registry has not yet refreshed. A finding is raised when any of the following are true: pwdLastSet on a trustedDomain object is older than 30 days; DisablePasswordChange = 1 on any DC; MaximumPasswordAge > 30 on any DC; RefusePasswordChange = 1 on any DC that holds a trust head; or the trustAuthOutgoing kvno has not incremented in the last two rotation windows.
Por qué importa
The inter-realm trust key is the cross-forest equivalent of krbtgt. Any principal who can extract that key can forge inter-realm referral tickets (TGTs that the trusting domains KDC will accept on the strength of the shared key) for arbitrary users in the trusted domain, with arbitrary group SIDs in the PAC, for the full lifetime of the key. Mimikatz lsadump::trust /patch extracts the key directly from LSASS on any DC; DCSync against the trust account (TRUSTED_DOMAIN$ or DOMAIN$) extracts it remotely with only Replicating Directory Changes rights. Once extracted, the only thing that invalidates the key is rotation: every 30 days the legitimate Netlogon process bumps the kvno and the prior key is retired (one previous version is kept to handle in-flight tickets, then discarded on the next rotation). When rotation silently fails, that 30-day exposure window becomes open-ended. Real environments routinely have trust keys that are several years old: the trust was created during a merger, the partner forest was deprovisioned without removing the trust object, or a Group Policy from 2009 set MaximumPasswordAge to 999 and was never revisited. Benjamin Delpys "Golden Trust" technique (analogous to a Golden Ticket but signed with the trust key rather than krbtgt) becomes a permanent forest-spanning backdoor: the attacker recovers the key once, exfiltrates it, and uses it to mint TGTs against the trusting forest for as long as the kvno on the trustedDomain object remains unchanged. Detection is hard because the forged tickets look like legitimate cross-forest referrals to the trusting DC, with no Event 4625 or 4768 anomaly to flag. The blast radius depends on which other ADTRUST controls are present. Combined with SID filtering disabled (ADTRUST-002), the attacker can inject Enterprise Admin SIDs of the trusting forest into the forged ticket. Combined with TGT delegation enabled (ADTRUST-003), the attacker can chain to unconstrained delegation primitives. Even with both mitigations in place, the attacker still gets authentication as any user in the trusted domain into resources the trust authorizes, which is enough for lateral movement, data theft, and onward escalation.
Ruta de ataque
Step 1: Reconnaissance. The attacker, holding any authenticated foothold in the trusted forest, enumerates trusts with Get-ADTrust -Filter * or nltest /domain_trusts /all_trusts and identifies trusts with a stale pwdLastSet via Get-ADObject -Filter {ObjectClass -eq "trustedDomain"} -Properties pwdLastSet, trustPartner. Trusts older than 30 days are candidates: the longer the key has been live, the more time the attacker has to operate before forced rotation. Step 2: Trust key extraction. With Domain Admin (or SYSTEM on a DC), the attacker runs mimikatz lsadump::trust /patch on a domain controller. The command prints the current and previous inter-realm keys for every trust the DC participates in, in RC4-HMAC, AES128, and AES256 forms, along with the kvno. Alternatively, with Replicating Directory Changes (DCSync) rights, the attacker runs secretsdump.py -just-dc-user TRUSTED$ DOMAIN/user@DC and pulls the same material remotely without touching LSASS. Step 3: Key durability check. The attacker records the kvno and compares it to subsequent enumeration. If pwdLastSet has not changed in 30+ days and trustAuthOutgoing kvno has not incremented, the extracted key remains valid indefinitely. If MaximumPasswordAge is set high (visible via reg query \\DC\HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters or via Group Policy enumeration), the key is durable for the configured interval. Step 4: Golden Trust forgery. The attacker forges an inter-realm referral TGT signed with the recovered key. Mimikatz: kerberos::golden /domain:trusted.local /sid:<trusted-SID> /sids:<trusting-EA-SID> /rc4:<trustkey> /user:Administrator /service:krbtgt /target:trusting.local /ticket:trust.kirbi. Impacket: ticketer.py -nthash <trustkey> -domain-sid <trusted-SID> -domain trusted.local -extra-sid <trusting-EA-SID> -spn krbtgt/trusting.local Administrator. The resulting ticket is an inter-realm TGT (krbtgt/trusting.local@trusted.local) that the trusting forests KDC accepts as a legitimate referral. Step 5: Service ticket exchange. The attacker presents the forged inter-realm TGT to the trusting domains KDC (asktgs / Rubeus asktgs / Impacket getST) and requests a service ticket for any SPN in the trusting domain. The KDC, seeing a valid inter-realm signature, issues the service ticket with the requested user identity and (if SID filtering is disabled) the injected ExtraSids. Step 6: Persistence. Because the trust key is not rotated, the attacker can repeat steps 4 and 5 indefinitely. Even if the attackers original foothold in the trusted forest is detected and remediated, the recovered trust key continues to grant cross-forest authentication. The only effective remediation is to reset the trust on both sides (netdom trust ... /reset /passwordt:<new>), which bumps the kvno and invalidates the previously recovered material.
Cómo lo evalúa Guerrilla
Guerrilla binds to each domain in (Get-ADForest).Domains and enumerates trustedDomain objects under CN=System with an LDAP filter of (objectClass=trustedDomain), requesting the attributes pwdLastSet, trustPartner, trustDirection, trustType, trustAttributes, trustAuthOutgoing, trustAuthIncoming, whenChanged, and msDS-TrustForestTrustInfo. pwdLastSet is converted from FILETIME to a UTC timestamp and the delta from now() is computed in days. Any value greater than 30 days raises a finding; values greater than 90 days are escalated to High severity. The trustAuthOutgoing blob is parsed for the kvno field and the count of historical keys: if only one key is present (no previous key), the trust has either never rotated or the previous key was discarded without a successful rotation in between. For the Netlogon registry side, the check iterates every domain controller returned by Get-ADDomainController -Filter * and reads HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange, MaximumPasswordAge, and RefusePasswordChange via remote registry (with a fallback to WinRM Invoke-Command Get-ItemProperty). Any DC reporting DisablePasswordChange = 1, MaximumPasswordAge > 30, or RefusePasswordChange = 1 is captured. The check also resolves the effective Group Policy on the Domain Controllers OU by inspecting GptTmpl.inf under SYSVOL for the corresponding RegistryValues entries and surfaces the originating GPO name so the operator knows what to edit. Finally, the check optionally calls netdom trust <trusting> /domain:<trusted> /verify against a sample of trusts to confirm the secure channel is healthy. A failing verify on a trust whose pwdLastSet is fresh indicates that rotation completed on the DS side but the secure channel between Netlogon services is broken, a state that will cause the next rotation to fail silently. Results are emitted as one row per trust with KeyAgeDays, KVNO, PreviousKeyPresent, DisablePasswordChangeAnywhere, MaxPasswordAgeMax, and SecureChannelHealthy columns.
Valor recomendado
Trust passwords rotated within the last 30 days. Automatic trust password rotation not disabled
Remediación
Check the trust password last set date by examining the trustAuthOutgoing attribute or running 'netdom trust /domain:trusted.domain /verify'. If the trust password is stale, reset it using 'netdom trust /domain:trusted.domain /Reset'. Verify that no GPO or registry setting has disabled automatic trust password rotation
Veredictos probados con fixtures
Cada veredicto de esta tabla está probado por un fixture de referencia en la suite de pruebas que valida el módulo. La tabla se deriva de la última ejecución en verde; no puede editarse a mano.
| Escenario | Veredicto esperado |
|---|---|
| clean | PASS |
| known-bad | WARN |
| throttled | Not Assessed |
Mapeos a marcos de referencia
- NIST SP 800-53
- IA-5(1), SC-12
- CIS AD Benchmark
- 3.2.4
- MITRE ATT&CK
- T1482, T1550.003