Breached password detection with Azure AD

Combine on-premises breached password reset detection with your cloud environment!


This post serves to demonstrate the ability to implement on-premises breached password checking in a hybrid Azure AD environment that allows for self-service password resets.

This is more of a proof-of-concept than an explicit guide – you may well find that the information outlined here does not meet your business requirements. I mostly wanted to confirm that this was indeed possible.

In this instance, I’ll be using my Pwned Passwords password filter on the on-premises side for detection, however you could use any of the various password filters around.

End Goals

By combining the information outlined here with a DLL like my Pwned Passwords filter on-premises, alongside my C# project to detect in-use breached passwords, you could theoretically eradicate breached passwords from your hybrid environment 🙂


In order to implement breached password reset detection for Azure AD, you’ll need

  • A breached password filter on your on-premises domain controllers
  • One of the following licenses on your tenant (for self-service password resets):
    Azure AD Premium P1
    Azure AD Premium P2
    Enterprise Mobility + Security E3 or A3
    Enterprise Mobility + Security E5 or A5
    Microsoft 365 E3 or A3
    Microsoft 365 E5 or A5
    Microsoft 365 F1
    Microsoft 365 Business

Getting Started

To start with, you’ll need a password filter on-premises. While you definitely don’t need to go with my filter, I’ve put some general instructions at the end of my first post here.

Once you’ve got an on-premises solution deployed, you’ll need to enable Azure AD Connect with password writeback – it’s the password writeback requirement that will require Azure self-service resets to be verified against your on-premises domain’s password requirements.

Posts such as this one do a great job of explaining how to set up password writeback, even going to great detail to discuss what permissions are required for the AD Connect account.

However, I’ll give a quick rundown on the process –

  1. On your AAD Connect server, start the Azure AD Connect configuration wizard
  2. Choose ‘Customise synchronisation options’
  3. Connect to Azure AD
  4. Select relevant OUs or domain filters
  5. On the ‘Optional features’ page, select ‘Password writeback’
  6. Select ‘Configure’

Once password writeback is successfully configured, you’ll need to allow your users to have access to self-service password resets in Azure.

This is somewhat more involved, especially if you’re rolling this out to a large amount of users. Once again, Microsoft have some great docs on planning deployment of self-service resets, through to actual deployment and testing.

Once you’ve got your self-service password reset portal in place, all that’s left to do is test it with a non-Administrator user, with a known breached password, and observe the result!


Thanks for reading. This has been my fourth, and likely final, post covering Troy Hunt’s amazing Pwned Passwords service. Through this series of posts, I’ve covered on-premises breached password reset detection, to utilising the online k-Anonymity model with resets, as well as checking currently used passwords against the data set.

With this post, I hope to have covered all possible facets, but I’m sure I’ve missed something somewhere, so please let me know if that’s the case!

As always, if you have any issues with anything here, or would like any extra information/further projects, please let me know 🙂

Pwned Passwords and NTLM Hashes!


Yep, another Pwned Passwords post! This one brings the total to 3, and it now makes up the entirety of my posts here.

A couple of days ago, Troy Hunt released support for NTLM hashes for his Pwned Passwords dataset. This is really cool because it allows us to check live Active Directory hashes from ntds.dit (located under C:\Windows\NTDS on Domain Controllers). However, there’s a little bit of work involved in getting to that step, so I thought I would put together this quick little guide.

Extracting Hashes from NTDS.DIT

So, how do we get the hashes out of that ntds.dit database?

There’s actually a few different ways, but the easiest I found from some cursory searching was to use Michael Grafnetter’s amazing PowerShell tool, DSInternals. If you don’t want to go about doing a manual install of it, you can get it straight from the PowerShell Gallery, with quick instructions here.

Once you’ve got it installed, the next step is to make a copy of ntds.dit. If you try directly from C:\Windows\NTDS, you’ll notice the file is locked. Again, there’s a few ways around this, but a quick way is to do a shadow copy of the system drive, copy it from the shadow copy, and then delete the shadow copy, like so –

Then, you need the SYSTEM registry hive. Luckily, this can be directly saved, by running –


Now that we’ve got both of those files, we can start extracting hashes!

With the system extract and ntds.dit copy in hand, fire up PowerShell, it’s time for DSInternals!

Running the following will extract the hashes in Hashcat format (necessary for the next step) –

$key = Get-BootKey -SystemHivePath '<PATH TO SYSTEM HIVE HERE>'
Get-ADDBAccount -All -DBPath '<PATH TO NTDIS.DIT HERE>' -BootKey $key | Format-Custom -View HashcatNT | Out-File <OUTPUT PATH HERE> -Encoding ASCII

Note: If you receive any errors about your ntds.dit file being invalid, this is a good guide to fix it. Essentially, you just need to run this command on the ntds.dit copy from a Domain Controller –

esentutl /p <PATH TO NTDS.DIT> /8 /o

Comparing the Hashes

Now that we have a neat little hash extraction, we can get to comparing our users’ passwords against the Pwned Passwords dataset. If you don’t have a copy of the NTLM hashes, you’ll need to grab them from here.

In Troy’s original post about adding NTLM hashes, he mentioned a tool to compare the passwords from Pwned Passwords with extracted passwords. This tool is available here. Unfortunately, as it builds a hashmap from a large text file, it’s not that fast.

Once downloaded, all you need to do is specify the function, and supply it with the path to the output file from the previous step, alongside the path to the pwned passwords dataset. The syntax and an example of the output can be seen below –

Note: The time is not representative of the full dataset, this was an example where the hash dictionary contained only the single hash. When using the actual dataset, it will take more than a few minutes (on average) per user.

So, now we know which users are currently using a breached password!

A Look at Faster Comparisons

While the tool above is certainly good, it just doesn’t scale too well. There’s also another great looking tool here, but again, the issue is speed. Definitely cool though! I decided to have a look at changing my original binary search for the original Pwned Passwords dataset (read my post here if you want more information on that).

As binary search requires a sorted input file, and the dataset is ordered by frequency, I went about sorting it myself. The sorting took about 40 minutes, but that’s on some pretty old hardware, and a pretty basic set up. It would be great to have the hashes available sorted by hash, but it’s not too bad if you have to do it yourself. I’d publish the sorted dataset but I don’t think my Australian internet would ever finish the upload.

In any case, I’m sure you could find a better sorting algorithm out there, but I used this and grabbed the necessary Priority Queue and Heap classes from the author’s GitHub. You’ll also need to modify it to ensure the frequency isn’t included when sorting.

You can find my code at my GitHub. Here’s an example of the syntax and the output –

There’s also a release available if you don’t want to compile it yourself.

Final Comments

I think the addition of NTLM hashes to the Pwned Passwords family will offer up even more use cases for the data. I’ve said it before, but it really needs to be said that Troy’s work is invaluable. He provides a great service to the infosec community.

I believe that the combination of this, alongside something to check against password changes (like my Pwned Passwords API checker, or the several others out there), will greatly help security folk, and hopefully help users see just how insecure some passwords are.

If you’ve made it this far, congratulations. I hope you have a great rest of your day/night! 🙂

Checking for Breached Passwords in Active Directory – Using k-Anonymity!

I’d like to preface this post by saying that I 100% understand concerns about using an external API, even when sending it just a small amount of unusable information. The possibility of compromise and subsequent infection on Domain Controllers is a true security risk and it is totally acceptable to not want to take that risk. For those not wishing to use an external API at all, I wrote an original post on checking breached passwords with AD, that works entirely offline with downloaded hashes of Troy Hunt’s Pwned Passwords – you can read about that project here.


Last year Troy Hunt released a freely searchable database of previously breached passwords. The available data was pretty much a godsend for anyone looking to verify that their users aren’t using breached passwords, with the ability to query for passwords through plaintext or as SHA1 hashes via API, as well as the ability to download the entire data set to use offline. A little after the release of this information, I wrote a DLL for use in Active Directory environments. However, that tool required users to download the massive lists of passwords so that it could be queried over the network. While it requires no external service interaction, it still requires downloading and searching through gigabytes of files.

Continue reading “Checking for Breached Passwords in Active Directory – Using k-Anonymity!”

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 –

Continue reading “Checking for Breached Passwords in Active Directory”