Abusing Users Configured with Unconstrained Delegation
Posted on Sun 15 March 2020 in Active Directory
An interesting situation came up on a recent assessment which triggered me into do a bit of research in the area as I'd seen nothing published on this particular issue.
I'd been really interested in the research done on the area of Kerberos Delegation. For this post, I'll be discussing Unconstrained Delegation, which has been covered a great deal in other places, notably here by Sean Metcalf and here by Dirk-jan Mollema, amongst others. If you really want to understand what is going on here, it might be best to read their work and understand it before continuing, although I'll try to give a recap here.
Unconstrained Delegation 101
In a nutshell, unconstrained delegation is when a user or computer has been granted the ability to impersonate users in an Active Directory domain with the only restriction of those contained within the Protected Users group or marked Sensitive and cannot be delegated.
What happens in short (read Sean's post if you want a detailed explaination, that's where this section is plagiarised from), after a user has already authenticated and wants to access a service that's been configured for unconstrained delegation:
-
The user presents it's TGT to th DC when requesting a service ticket.
-
The DC opens the TGT & validates PAC checksum – If the DC can open the ticket & the checksum check out, the TGT is valid. The data in the TGT is effectively copied to create the service ticket. The DC places a copy of the user’s TGT into the service ticket.
-
The service ticket is encrypted using the target service accounts’ NTLM password hash and sent to the user (TGS-REP).
-
The user connects to the server hosting the service on the appropriate port & presents the service ticket (AP-REQ). The service opens the service ticket using its NTLM password hash.
The diagram below (also taken from Sean's post) shows the full process:
The Situation
While abusing unconstrained delegation has been covered in detail many times, all of these posts address machine accounts, I've not yet seen anything related to abusing users configured for unconstrained delegation.
The setup for the demo is simple. A domain internal.zeroday.lab, with a domain controller IDC1 and a user TestUCSPN which has been configured for unconstrained delegation, as can be seen below:
As shown, the TrustedForDelegation attribute is set to True and the ServicePrincipalName is set to cifs/notexist.internal.zeroday.lab. The cifs service is being used here purly for convinence in demonstrating the issue.
The DNS record for notexist.internal.zeroday.lab does not exist:
This is all that is required to exploit it because the password for the machine account is not needed, but in this example the machine account also doesn't exist:
This allows me to demonstrate that it is still exploitable, by creating the machine account, using Kevin Robertson's Powermad:
Abuse
While it doesn't matter if the machine account is created in Active Directory, the DNS record needs to not exist for this attack to work (or it needs to point to a machine under your control).
If the DNS record doesn't exist, like in this example, it's easy to create one using any valid domain user account. Here I'm using Dirk-jan Mollema's krbrelayx:
Here 192.168.71.198 is the IP address of a Linux system under my control.
Sometimes it takes a little while for the name to resolve so it's good to check before continuing:
Now everything is in place to abuse this configuration. First, we need the hash of the service account's password (TestUCSPN in this case). For this Benjamin Delpy's tool mimikatz does the job nicely:
To retrieve the target's TGT ticket, we'll again use Dirk-jan Mollema's krbrelayx:
And from the same repository the printerbug.py script to trigger the authentication from the domain controller (192.168.71.20) to the target SPN host (notexist.internal.zeroday.lab):
This coerces the domain controller to authentication to the CIFS service on host noexist.internal.zeroday.lab where the krbrelayx.py script is listening. The krbrelatx.py script saves the ticket in ccache format:
This saved the ticket in the current working directory with the name [email protected][email protected].
For some reason, converting it to kirbi format using krbrelayx.py was failing with the error below:
Of course, you could using the ccache format with impacket but I decided to use Will Schroeder's Rubeus so I needed the ticket in kirbi format.
To convert the ticket I used Zer1t0's ticket_converter and then base64 encoded it:
This is now usable by Rubeus.
First, to demonstrate the a DCSync is not possible from the current context, mimikatz was used:
Lastly, Rubeus is used to inject the ticket into the current context and then mimikatz is able to perform a DCSync of the KRBTGT account from the domain controller:
Conclusion
One of the interesting things I find about attacks like this is here I used the TGT for the domain controller IDC1 to perform a DCSync from the same domain controller IDC1. I'm not sure why this is possible as I can see no reason why a domain controller would need to synchronize with itself, but it works...
This post is, as far as I've seen, the first explaination of how to take advantage of unconstrained delegation without requiring to compromise any machines and while it's most likely an uncommon situation, I have seen this in the wild recently.
Kerberos delegation is a really interesting point of research and I'm sure there will be plenty more research coming out in the future so it's well worth getting up to date with the current research out there.