Re-becoming the securest constrained delegation we never weren’t

When performing Active Directory security assessments, I often come across servers or identities with unconstrained delegation or legacy delegation – In this blog post I will show you how to eliminate unconstrained delegation by using resource-based constrained delegation (RBCD). The RBCD will be configured between group Managed Service Accounts (gMSA) to ensure no SPNs get roasted today. The reason behind using unconstrained delegation is usually that a vendor requires it, which shouldn’t be accepted. Following this blog will show you how unconstrained delegation can be changed to resource-based constrained delegation quickly.

Attacking servers with unconstrained delegation can yield quick privilege escalation in the Active Directory, since the attacker can forward privileged users TGT to any service in the domain. If your IIS is currently configured for unconstrained delegation, I might be able to Kerberoast your regular service account, log in to the IIS server and make a domain administrator connect to any service on the IIS server. Getting a privileged account to connect to the IIS server, could be done with crashing services or having the CPU spike to 90+% load. Typically, this would create an alert in the monitoring solution, enabling an administrator to connect to the compromised server. Once the administrator has authenticated against the compromised server, I’ll simply use mimikatz ‘sekurlsa::tickets /export’ to retrieve the administrators TGT and compromise the entire domain.

If you currently do not know which objects have been configured with unconstrained delegation in your Active Directory environment, please grab the PowerShell script ‘Search-KerbDelegatedAccounts.ps1’ from https://gallery.technet.microsoft.com/scriptcenter/Find-all-accounts-using-04658a99 and run it on a domain-joined system with a domain user. Only ‘Authenticated Users’ permissions are required to retrieve this information.

Regular service accounts, user object with SPN configured, will always be prone to attacks such as Kerberoasting, Silver Tickets, password spraying and more. Another misconfiguration I often see is that service accounts are not denied access to any computers in any logon type – If I successfully crack a kerberoasted service account, I should not be able to RDP to servers or spawn shells with RunAs; however, I almost always is.

Utilizing “Deny log on locally”, “Deny log on through Remote Desktop Services” and “Deny access to this computer from the network” for service accounts should be required in any organization. These simple User Rights Assignment settings could potentially stop low-skilled adversaries or automated exploitation tools. I often see service accounts are a member of other security groups, which has been granted “Log on locally” or “Log on through Remote Desktop Services”, therefore I recommend using the “Deny log on …” settings to ensure that local logon or RDP is not possible.

Running services with gMSA, if supported, is easily done in any Windows environment. Many Windows applications support gMSA as well as third party application so unless your desired application does not support this, you should deploy them immediately.

Maybe I should explain gMSA before pushing you to deploy; Group Managed Service Accounts is a new and better edition of old regular service accounts, which is basically a user object with a SPN set. gMSA is a domain account/object which automatically manages passwords, helps simplify SPN configuration and management and is restricted to specific servers to ensure that any requesting server is not able to retrieve the password. With this managed password you do not have to worry about attackers successfully cracking it, since the KDC will automatically roll it every 30 days (unless changed by you) and the password is 128 UTF-16 characters.

In essence, gMSA is here to retire regular service accounts, by providing a default least-privilege and password worry-free service account.

Furthermore, setting up RBCD with gMSA has never been easier! Let’s begin by defining our scenario.

I’ve deployed on-premises Active Directory (Tiered of course) and I need delegation between my internal IIS hosting our intranet and my internal MSSQL server hosting the database required for showing stats and more on the intranet website.

Objects involved:

  • Active Directory – AD.IMPROSEC.COM

  • IMPRO-DC – Domain Controller (Server 2019)

  • IMPRO-IIS – Internet Information Services (Server 2019)

  • IIS-gMSA – Group Managed Service Account for IIS

  • IMRPO-SQL – MSSQL database (Server 2019)

  • SQL-gMSA – Group Managed Service Account for SQL

  • IIS-Cluster – Security Group for the IIS server

  • SQL-Cluster – Security Group for the SQL server

  • Tier1_AllAccounts – Security Group for Tier 1 administrator accounts providing local administrator access

  • IMPRO-W10 – Regular Windows 10 workstation

  • nfalk – Regular user identity for accessing intranet and testing RBCD

  • tier1_nfalk – Local administrator on Tier 1 servers (IIS,MSSQL)

  • tier0_nfalk – Domain Administrator

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Deployment phase:

Initially we need a KDS Root Key. This KDS Root Key is required for Domain Controllers to generate gMSA passwords.

Execute the following PowerShell command on a Domain Controller:

Add-KdsRootKey

The KDS Root Key will not be available before 10 hours has passed, to ensure that all Domain Controllers have successfully replicated the key. Since this is a lab, I’ll reduce that time, granting me the ability to utilize it immediately:

Add-KdsRootKey -EffectiveTime ((get-date).addhours(-10))

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Now that the KDS Root Key is created, let’s create our new gMSA for IIS and SQL, execute the following PowerShell commands on a Domain Controller:

New-ADServiceAccount -Name "IIS-gMSA" -DNSHostName "IIS-gMSA.AD.IMPROSEC.COM" -PrincipalsAllowedToRetrieveManagedPassword IISCluster -Enabled:$true

New-ADServiceAccount -Name "SQL-gMSA" -DNSHostName "SQL-gMSA.AD.IMPROSEC.COM" -PrincipalsAllowedToRetrieveManagedPassword SQLCluster -Enabled:$true

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

The service accounts have been created and members of “IISCluster” and “SQLCluster” can successfully retrieve the managed passwords.

Executing the following PowerShell commands should now return our two accounts:

Get-ADServiceAccount -Filter * | Select-Object Name,DistinguishedName

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

And we can see they are placed in the “Managed Service Accounts” OU.

Looking at the SamAccountName we can see a ‘$’ at the end of their names, this will be utilized later when adding the service accounts to desired servers and applications:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

One thing that Microsoft mentions about gMSA is that they automatically set, unset and manage SPNs which is great! No more dealing with setspn.exe, our gMSA will take care of business. Not too much actually… I noticed that automatically setting SPNs for the SQL didn’t work in my lab, unless I changed the ACEs associated with the gMSA, but your mileage may vary. If automatically setting SPNs does not work in your Active Directory either, please grant the gMSA itself access to ‘Read’ its own servicePrincipalNames property. In my case, SQL-gMSA already had ‘Write’ but without ‘Read’ it was not able to set SPNs.

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Creating and SPN handling is now done and we’re ready to install the gMSAs on the servers.

Log in to the IIS server as a local administrator and ensure ADDS PowerShell modules is installed and execute the following PowerShell commands:

Install-ADServiceAccount IIS-gMSA

Test-ADServiceAccount IIS-gMSA


If all goes well the Test-ADServiceAccount should return True:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Now repeat the same steps on the MSSQL server, but install the SQL-gMSA:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Now our gMASs have been created and successfully installed on the associated servers.

If Test-ADServiceAccount returns ‘False’, please review which server has access to retrieve the managed password

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Time to configure our resource-based constrained delegation, which can be achieved by this simple PowerShell command executed on a Domain Controller:

Set-ADServiceAccount SQL-gMSA -PrincipalsAllowedToDelegateToAccount (Get-ADServiceAccount IIS-gMSA)

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

What it essentially does is telling the SQL-gMSA that any forwarded (delegated) tickets retrieved from the IIS-gMSA account should be accepted.

Let’s finalize our IIS and SQL configuration – First, go to the IIS server and open the IIS Manager.

I’ve already created a new application pool and setup a basic website for testing constrained delegation. The name of my application pool is ‘CONSTRAINED’ and now I’m going to enter ‘Advanced Settings’ on CONSTRAINED. Now navigate to ‘Identity’ and type in IMPROSEC\IIS-gMSA$

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Now navigate to the CONSTRAINED site and make sure ‘ASP.NET Impersonation’ and ‘Windows Authentication’ is enabled:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Navigate to the ‘Configuration Editor’ and select ‘system.webServer/security/authentication/windowsAuthentication’ and make sure that ‘useKernelMode’ is set to False and that ‘useAppPoolCredentials’ is set to True.

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

The final check is to make sure that ‘Managed pipeline mode’ is set to ‘Integrated’ for our CONSTRAINED application pool:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Extended Protection with Channel-binding could also be enabled; however, this is out-of-scope for this blog post.

It is possible that the Web.config file must be edited to suppress warnings when attempting to delegate. In that case, use the following parameters:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Lastly, we need to configure our SQL Server to utilize this gMSA.

I’ve logged into IMPRO-SQL and found the ‘SQL Server’ service running my named instance called ‘CONSTRAINED’. Now type in IMPROSEC\SQL-gMSA$ (Remember the ‘$’) and click OK. The service is now running with our gMSA. Repeat the same process for the ‘SQL Server Agent (CONSTRAINED)’ service.

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

In some cases, the SQL services won’t start when the SQL server is restarted, when gMSA is implemented on the services. Please set the services to ‘Automatic (Delayed Start)’:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Both our services should now look like this:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

For testing purposes I’ve created a login for IMPROSEC\nfalk to ensure that I can access the database:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Let’s test the configuration and see if RBCD actually works.

Log into the Windows 10 workstation using nfalk and access http://impro-iis/

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Initially, we have seen the website recognizes our nfalk account, which means that Windows Authentication works.

I’ve placed the SQL backend in http://impro-iis/People and created a simple panel for viewing, adding and deleting information in the CONSTRAINED database:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

Returning to IMRPO-SQL we can see that nfalk has open connections through IMPRO-IIS using Kerberos authentication:

Re-becoming the securest constrained delegation we never weren’t by Nichlas Falk

This is it for setting up a secure IIS to MSSQL resource-based constrained delegation.

Setting up RBCD with gMSA is a simple task and any vendor trying to convince you that unconstrained delegation is required, should not be allowed to configure their service or application in your Active Directory.

Replacing unconstrained delegation with RBCD between gMSA ensures that any malicious adversaries won’t be able to forward privileged Kerberos tickets to e.g. the LDAP service on a Domain Controller and perform the DCSync attack.