Edit: I have now overhauled the blog post and essentially recreated PwnedPasswordsDLL to run on-premises, and return results very quickly. Information regarding set-up and the new release can be found below. Changes have now been pushed to GitHub and are available for use.
In simplistic terms, PwnedPasswordsDLL will check a requested Active Direvtory password change against a local store of over 330 million password hashes. If the hash is found in the breached passwords, the requesting password is rejected. This entire process takes ~1 second against over 330 million previously breached password hashes.
Now on to a more technical explanation.
A little known setting through LSASS on Windows PCs is the ability to call a custom filter DLL when a password change request is received. The utilisation of this resource was commonplace back in the Windows 2000 days, but it’s now seldom used; many sysadmins are happy enough using totally third-party solutions or the in-built Group Policy settings.
The concept of a 100% customisable password filter intrigued me, and with Troy Hunt’s new freely searchable database of pwned passwords, I decided to look at setting up a filter DLL to call a local store of the breached passwords to check the prospective password change.
I discovered that writing such a DLL was a very simple process, most of the actual handling of the DLL is done internally, all that needs to be done by an author is to create a function that returns a Boolean expression based around whether or not conditions are met for the requesting password. The result of my research is PwnedPasswordsDLL.
In calling the DLL, the requested password is converted to an SHA1 hash through the Crypto++ library. This SHA1 hash is then passed to a binary search algorithm I wrote that searches the three HaveIBeenPwned breached passwords text files. If the hash is found, a false boolean is returned (i.e. telling LSA that the calling password failed to meet the required password policy).
If you’re willing to give it a whirl, you can find the code here.
Here is an example of the DLL in use –