Skip to content

NTLM Hashes Explained: How Windows Stores Passwords

How the NTLM hash works — MD4 of the UTF-16LE password, no salt, no iterations — why NTLM hashes crack fast, pass-the-hash, and how NTLMv2 authentication differs.

Published on 9 min read

Few hashes carry as much operational weight — or as much confusion — as the NTLM hash. It is the value pentesters dump from a domain controller, the secret that fuels pass-the-hash attacks, and the thing people mean (usually) when they say "Windows password hash." Yet most descriptions blur two very different things together: the stored secret and the authentication protocol. This article pulls them apart, shows exactly how the hash is computed, and explains why a value that defends a billion-dollar enterprise is, by modern standards, almost trivially weak at rest.

What the NTLM hash actually is

The NTLM hash — more precisely the NT hash — is one of the simplest constructions in all of credential storage. There is no salt, no key stretching, no clever construction. It is a single, unmodified application of the MD4 hash function to the password after that password has been re-encoded into UTF-16 little-endian:

NT hash = MD4( UTF-16LE( password ) )

That is the entire algorithm. A 32-character lowercase hex string (128 bits) comes out, and that string is what Windows stores and what it uses as the cryptographic key during network authentication. The terms "NT hash" and "NTLM hash" are used interchangeably; "NTLM" technically refers to the authentication protocol family, but in practice the dumped hash is universally called an NTLM hash.

The UTF-16LE encoding step

The one detail people get wrong is the encoding. The password is not hashed as ASCII or UTF-8. Windows first converts the string to UTF-16 little-endian, meaning every code unit becomes two bytes with the low byte first.

The password Pass is not the four bytes 50 61 73 73. It becomes eight bytes:

P     a     s     s
50 00 61 00 73 00 73 00

Each character is followed by a 00 byte (for characters in the Basic Latin range). Those zero bytes are part of what gets fed into MD4. If you ever compute an NTLM hash by hand or in a script and get the wrong answer, skipping the UTF-16LE conversion is almost always the cause.

Worked pseudocode

input    : "password"
step 1   : utf16le("password")
           = 70 00 61 00 73 00 73 00 77 00 6f 00 72 00 64 00
step 2   : MD4(step 1)
step 3   : hex-encode the 16-byte digest
output   : 8846f7eaee8fb117ad06bdd830b7586c

That final value, 8846f7eaee8fb117ad06bdd830b7586c, is the well-known NT hash of the literal string password. Because the algorithm is deterministic and unsalted, every Windows machine on Earth produces that identical hash for that password.

Where it is stored

On a standalone or workgroup machine, NT hashes live in the SAM (Security Account Manager), a registry hive backed by %SystemRoot%\System32\config\SAM. The hashes are obfuscated with a per-system key called the SysKey/bootkey, but that protection is local: anyone who can read the SAM and the SYSTEM hive (which holds the bootkey) can recover the raw NT hashes.

On a domain controller, all domain account hashes are stored in the Active Directory database, NTDS.dit, typically at %SystemRoot%\NTDS\NTDS.dit. Dumping NTDS.dit — via ntdsutil, a volume shadow copy, or DCSync over the replication protocol — yields the NT hash for every account in the domain, including the krbtgt account. This is why domain-controller compromise is catastrophic: it hands the attacker the keys to every identity at once.

The LM hash it replaced

Before the NT hash, Windows used the LM (LAN Manager) hash, and it was dramatically worse. LM took the password, uppercased it, padded or truncated it to exactly 14 characters, split it into two independent 7-character halves, and DES-encrypted a fixed constant with each half as a key.

The consequences were brutal:

  • Case was discarded, shrinking the keyspace.
  • The 14-character cap meant longer passwords were ignored beyond that length.
  • The independent-halves design meant a 14-character password was really just two separate 7-character passwords — and a 7-character LM half can be brute-forced exhaustively in seconds on modern hardware. A blank second half (the famous AAD3B435B51404EE constant) instantly reveals the password is 7 characters or fewer.

The NT hash fixed the worst of this: it is case-sensitive, handles the full password length, and uses the whole string. But it kept the cardinal sin — no salt and no work factor — which is the real subject of this article.

Why this is weak for at-rest storage

The NT hash fails every property we now demand of a password-storage scheme. Three failures stack on top of each other.

No salt. Identical passwords always produce identical hashes, with no per-user randomization. This means precomputed rainbow tables work directly against NT hashes, and an attacker who dumps a database instantly sees which users share a password (every duplicate hash is a duplicate password). Salting exists precisely to defeat both, and the NT hash has none.

No iteration or work factor. The NT hash is a single MD4 call. There is no cost parameter to slow an attacker down. MD4 is one of the fastest hash functions ever designed, and a modern GPU evaluates it at billions of candidates per second. An 8-character password drawn from a typical keyspace falls in hours; anything in a wordlist falls instantly. Purpose-built password hashes deliberately do the opposite, as covered in the guide to hashing passwords correctly.

MD4 is itself broken. MD4 is the older, weaker sibling of MD5, and MD5 is comprehensively broken — practical collisions, decades of cryptanalysis, and no security margin left. The same forces that broke MD5 apply with even more force to MD4. For the full picture of how a fast, unsalted hash collapses under attack, see why MD5 is broken; the underlying weaknesses are the same family of problems that doom the NT hash for storage.

If you want the conceptual foundation — what a hash function is, what salting and iteration buy you, and why "fast" is a vice for password storage — start with the pillar, how hashing works.

The crucial distinction: stored hash vs authentication protocol

Here is where almost everyone gets tangled. The NT hash is the stored secret. The NTLM protocol is a separate challenge-response handshake that uses that stored hash as a cryptographic key. They are not the same thing, and improving one does not improve the other.

The protocol works, roughly, like this:

client  -> server : I want to authenticate
server  -> client : here is a random challenge (nonce)
client  -> server : response = function( NT hash, challenge )
server            : verifies by computing the same function with its copy of the NT hash

The plaintext password never crosses the wire. The NT hash is the key that encrypts/HMACs the server's challenge. This is the heart of the confusion: the protocol genuinely avoids sending the password, which sounds secure — but the secret being used is still the unsalted, unstretched NT hash.

NTLMv1 vs NTLMv2

NTLMv1 built the response with a weak DES-based construction over the challenge, and it is recoverable/relayable in ways that make it dangerous; it should be disabled everywhere.

NTLMv2 improved the protocol: it uses an HMAC-MD5 construction, incorporates a client challenge and a timestamp, and binds more context into the response, which mitigates some replay and reflection attacks. This is a real improvement to the handshake.

But — and this is the point — NTLMv2 does not change the stored secret. The long-term key feeding the HMAC is still the plain NT hash, MD4(UTF-16LE(password)). NTLMv2 hardens how the secret is exchanged; it does nothing to harden how the secret is stored. The at-rest weaknesses above remain fully intact.

Pass-the-hash

Because the authentication protocol uses the NT hash directly as the key, an attacker does not need the plaintext password at all. If they can steal the hash — from SAM, from NTDS.dit, or from LSASS memory on a logged-in machine — they can feed it straight into the protocol and authenticate as that user. This is the pass-the-hash attack.

The hash is a password-equivalent. There is no "but they still need to crack it" safety net for lateral movement: the stolen 32-hex-character value is the credential. Tools like Mimikatz, secretsdump, and pth-winexe operationalize this. It is the single most important reason NTLM is treated as a liability in modern networks — the design that avoids transmitting the password also makes the hash as good as the password.

Defenses

You cannot add a salt or a work factor to the NT hash — it is fixed by the protocol. So defense focuses elsewhere:

  • Long, random passwords. The only at-rest mitigation available is keyspace. A 20+ character random passphrase pushes brute force out of reach even at billions of guesses per second. Enforce length, block known-breached passwords.
  • Disable LM and, where possible, NTLM. Turn off LM hash storage (NoLMHash), disable NTLMv1, and use Group Policy / audit logging to find and eliminate NTLM usage. Migrate to Kerberos, which uses a different model and supports stronger ticketing.
  • Credential protections. Enable Credential Guard to keep secrets out of reach in LSASS, restrict local admin reuse (LAPS), tier administrative accounts, and protect the krbtgt account. These limit how far a stolen hash travels.
  • Constrain the blast radius. Network segmentation, SMB signing, and disabling NTLM relay paths reduce what a passed hash can reach.

For application developers, the lesson is direct: never store passwords the way Windows stores NT hashes. A single fast unsalted hash is the textbook wrong answer. Use a purpose-built password hash with a tunable work factor — Argon2 is the current recommendation — and follow the password-hashing guide for salting, parameters, and migration strategy.

Generate and inspect NTLM hashes yourself

To see the algorithm in action — UTF-16LE encoding feeding a single MD4 pass — you can generate an NTLM hash in your browser with Hash Generator. The computation runs entirely client-side in WebAssembly; nothing you type is ever uploaded or logged. Paste a candidate password and watch the same 32-hex-character value Windows would store appear instantly. It is a fast, safe way to confirm that two identical passwords really do produce identical hashes, and to feel just how little work stands between an NT hash and the password behind it.

Conclusion

The NTLM/NT hash is a study in how a single design decision echoes for decades. MD4(UTF-16LE(password)) was adequate for an era of slow CPUs and trusted LANs; today it is unsalted, uniterated, and built on a broken primitive — fast to crack and, via pass-the-hash, usable without cracking at all. NTLMv2 improves the handshake but leaves the stored secret untouched, so the right strategy is to shrink NTLM's footprint, lean on Kerberos and credential protections, and demand long random passwords. And if you are storing passwords in your own application, do not imitate Windows: reach for Argon2. To experiment with the construction directly and privately, try Hash Generator.

Related articles

A practical guide to storing passwords securely in 2026 — why general hashes fail, salts vs peppers, work factors, and choosing Argon2id, scrypt, bcrypt or PBKDF2.
How bcrypt works — the Eksblowfish key schedule, cost factor, salt, and the $2b$ hash format — why slow adaptive hashing protects passwords, and bcrypt's limits.
How Argon2 works — memory-hard password hashing, the Argon2d/i/id variants, the memory, time and parallelism parameters, and why it beats bcrypt and PBKDF2.