Checking for Breached Passwords in Active Directory

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.

Introduction –

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.

If you want to compile for yourself, check out the Compiling the Code section below. If you want to download a Release version, look at the Implementing the DLL section below.

Here is an example of the DLL in use –


Compiling the Code –

The code is heavily reliant on the Crypto++ library in order to convert the calling password to a SHA1 hash.  I have also only tested the code on x64 architecture, so I’m not sure if it will even work on 32-bit systems.

Compiling the code is quite simple in Visual Studio –

  1. Download the PwnedPasswordsDLL source from here
  2. Download Crypto++ from the following link
  3. Build Crypto++ as a library in x64 mode – the following link is a good resource on compiling it for use in Visual Studio
  4. Include the Crypto++ header directories through Project –> PwnedPasswordsDLL Properties –> Configuration Properties –> VC++ Directories. Edit the Include Directories and add the include directory
  5. Then, edit the Library Directories and add the Debug directory from the x64\Outputdirectory.
  6. Add cryptlib.lib to your Additional Dependencies list under Project –> PwnedPasswordsDLL Properties –> Configuration Properties –> Linker–>Input–> Additional Dependencies
  7. Change Runtime Library to Multi-threaded Debug (/MTd) underProject –> PwnedPasswordsDLL Properties –> Configuration Properties –>  C/C++–> Code Generation
  8. All that’s left now is to Build and then test out the DLL!

Implementing the DLL –

The implementation of the DLL is the easy part, save for downloading some rather large text files – whether you’ve compiled the code yourself or downloaded a release, the implementation process is the same.

Note: These instructions need to be followed on all Domain Controllers in the domain if you wish to implement this for Active Directory, as any of them may end up servicing a password change request.

As the solution is entirely on-premises, you need to download the 3 breached passwords zip files from HaveIBeenPwned and extract the plain-text documents to the C drive (the file path is customisable if you compile the code yourself, but not if you download the Release). Note that you don’t have to do this for all Domain Controllers if you set up the DLL to read from a network share before compiling.

  1. Download and extract the breached password lists, as per the instructions above
  2. The DLL itself needs to be placed in your system root directory (generally C:\Windows\System32).
  3. The DLL name needs to be added to the multi-string “Notification Packages” subkey under HKLM\System\CurrentControlSet\Control\LSA – note that you only need to add the name of the DLL, not including the file extension.
  4. To ensure that the DLL works alongside your Group Policy password filtering settings,  ensure that the Passwords must meet complexity requirements policy setting is enabled through your relevant GPO(s).
  5. Reboot the PC(s). Any password change request should now be filtered through the DLL.
  • Kyle Hamilton

    …so you transmit proposed passwords to a third party in plaintext before letting the account set them?

    …and you think this *hasn’t* compromised those passwords?

    • Jackson

      Hi Kyle, if you’re interested, I’ve now changed the DLL to convert the calling password to a hash and work locally using a binary search algo on locally stored text files of over 330 million breached password hashes.

      • Kyle Hamilton

        I approve. :thumbsup: Thank you!

  • Pingback: Checking for Breached Password Requests in Active Directory - ZRaven Consulting()

  • Pingback: 【知识】8月15日 - 每日安全知识热点 - 莹莹之色()

  • Pingback: 【知识】8月15日 – 每日安全知识热点 – 安百科技()

  • Pingback: 【知识】8月15日 – 每日安全知识热点-安全路透社()

  • Pingback: On-Premises Breached Password Requests Checking in Active Directory - ZRaven Consulting()

  • Pingback: IT Security Weekend Catch Up – August 20, 2017 – BadCyber()

  • Peter Marsh

    I’m trying to use UNC paths for the password files, but not sure I have the correct syntax. Compiling went fine, but I can still successfully change the password to “Password1”.

    I removed the c:/password.text and replaced with \fileserverpasswords.txt. Should this work or is it expecting a different path format?

    • Jackson

      Hi Peter,
      Pretty sure you need double slashes each time you have a slash, I.e. \\server\file – pretty sure that’s the syntax in C

      • Peter Marsh

        That worked. Thanks!

  • EnviableOne

    wish I’d found this two weeks ago before I started working out myown in PowerShell

  • Jason Hanson

    Quick question- I am testing this in my lab and it appears to be working. I am using the code that you supplied rather than customizing. Is there an easy way to add a password to the list? I created a sha1 hash of a password that I didn’t want to allow and added it to pwned-passwords-update-2.txt. This does not appear to be working.

    • Jackson

      Hey Jason, not sure if you’ve resolved this yourself, it seems fine to me – definitely make sure you’re following the same format as the hashes in the text files, i.e. all caps. Otherwise, not really sure why that wouldn’t work. You could always create a new text file and add the SHA-1 hash there, then add it to the String array containing the filenames.

  • Jean

    Hi Jackson,

    Wow great project. I try to install the compiled DLL. I have 2 DC, and add into system32 folder for each, add registry key for both, and create a text file with Hash SHA1 in Caps to try specific password for a test user. But nothing I can use password that was in text file (In Hash SHA1).

    Computer here are in french and in englaish, try both, but the same. Domain controller are in french…do you thing that could be the issue?

    Regards,

    Jean-Sebastien

    • Jean

      I also try on DC : net user Joe.Bloe Welcome@17

      It’s work, and the hash was AC36CFEB1972AC89591657CB1D0DD2F2BF071B2D

      I use this to have the hash : echo -n Welcome@17 | sha1sum

      Any idea?

      Regards,

    • Jackson

      Hi Jean,

      Sorry for the late reply. The language shouldn’t be an issue. Did you add the SHA1 hash to one of the pwned passwords text documents? Using the compiled DLL, the DLL will look for the following text files in the C: drive:
      C:pwned-passwords-1.0.txt, C:pwned-passwords-update-1.txt, C:pwned-passwords-update-2.txt

      If you have any of these files in the root of the C drive on both DCs with the SHA1 hashes that you want to exclude then that should be fine. Let me know how it turns out 🙂