Password Protection – Made easy


Have you implemented it correctly?

In this article we’re having a look at the Azure Active Directory Password Protection system and why most companies aren’t configuring it correctly. The solution was created to protect users form making their passwords easily guessable by enforcing a banned list of passwords. The list is put through normal substitution and fuzzing before being handed over to the domain controller and can consist of hundreds of banned words.

First off: What is Azure Active Directory Password Protection? Microsoft in their incredible wisdom posted this picture to explain how it works:

Walking you through it the solution works like this from a user perspective:

  1. The user changes their password as usual. This could be through a solution like adaxes, ctrl+alt+del and password change or Self Service Password Reset (SSPR). It does not really matter through what system the password is changed, as it ultimately ends up at the same place.
  2. The password policy is evaluated agains the proposed new password. If the validation passes, then the password is written to Domain Controller LSASS and synced to the other domain controllers.
  3. If it doesn’t, the user will be presented with “The password is not accepted”. (I’m aware it’s a dumb error message, but don’t blame me), and the user is requested to try again.

On the server side, the system is even simpler. The solution consist of two agents and an internet connection:

First of all is the most important agent, the proxy agent. The reason for this two-stage solution is to isolate domain controllers from the internet, as per Microsoft’s own best practices in domain design – I’ve written about that here.
The important thing to keep in mind is why the proxy agent is integral to the way domain controllers get into contact with the banned passwords lists:

  1. Step:
    • The banned passwords list is created in Azure Active Directory, based on the standard-banned passwords lists Microsoft maintains (not available for perusal, annoyingly.) and the custom list you set in the portal.
  2. Step:
    • The proxy agent polls for an update on this list and downloads it. The list is then kept in storage on the proxy list server.
  3. Step:
    • The Domain Controller agent polls the proxy agent for the new list. The proxy agent may then trigger a poll for a new list or hand over the one it has available, but there is no list available (the proxy is not answering for instance) will the domain controller agent use the one it has in cache if it has one.

This is the first thing companies do wrong:
Implementers don’t install the proxy agent. In Norway, it’s common to allow the domain controller unrestricted access to the internet, leading implementers to disregard that part of the solution.

What’s interesting with this solution is how the agents find each other. The Domain Controller agent search for the proxy agent using a special object in Active Directory. If the object does not exist, the system waits for -n amount of seconds before making another search. If the proxy agent is not installed, the object will not show up in Active Directory leading us to problem number two:

Problem number two:
We now have both agents installed. Here’s where I see most organizations trail off. They believe the solution will automatically know what tenant the domain is controlled by and configure itself.

We expect too much of our computers. I have seen too many implementers closing the ticket marked with solution complete by just installing the server packages.

That’s not how this works.

You can check your current settings by running the following powershell commands:

Get-AzureADPasswordProtectionProxyConfiguration | format-list

and

Get-AzureADPasswordProtectionDCAgent | format-list

If you’re getting something like this in return:

ServerFQDN : DC01.McKinsley.global
SoftwareVersion : 1.2.125.0
Domain : McKinsley.global
Forest : McKinsley.global
PasswordPolicyDateUTC : 25.08.2022 11:59:45
HeartbeatUTC : 25.08.2022 12:00:06
AzureTenant :

Then you have exactly issue number two: Your solution is not configured to communicate with Azure for your banned password list. The application packages doesn’t natively know what Azure tenant your organization is connected to. This means the lists aren’t being exchanged and the domain controller agent has nothing to evaluate.

Problem number three:
Implementers register the domain controller agent, not the proxy agent. Simply, you can’t configure something the organization has not implemented.

This leads me over to part two of this article…

How to set up Azure AD Password Protection – the easy way

  1. Install the Domain Controller Agent on ALL domain controllers
  2. Install the Proxy Agent on at least two domain member servers
  3. Configure the agents using the following commands:

Register proxy agents:
Register-AzureADPasswordProtectionProxy -AccountUpn ‘[email protected]

Register domain controller agents:
Register-AzureADPasswordProtectionForest -AccountUpn ‘[email protected]

4. When this is complete, it should spit out something like this for each of your domain controllers:

ServerFQDN : DC01.McKinsley.global
SoftwareVersion : 1.2.125.0
Domain : McKinsley.global
Forest : McKinsley.global
PasswordPolicyDateUTC : 25.08.2022 11:59:45
HeartbeatUTC : 25.08.2022 12:00:06
AzureTenant : mckinsley.onmicrosoft.com <- If this is not present, you’re not done.

And then you can move over to my favourite part: Configuring the banned password list. You should set it somewhat like this:

In the event you’re in Norway, please remember to add both the year numbers from 1970 – present day and both the Norwegian and English names of the times of the year. Last time we did a password spray with only “Summer2020” we hit more than 20% of the users. This makes me whimper at night.

Make the list your own, and remember, users will find short routes if you’re not thurough.

How are the passwords evaluated?

Say you have the following parts on your list:
Summer
2022


And the user try to set the password “Summer2022”. This will of cause fail. The reason for this is because both Summer and 2022 are “banned” passwords. AADPP evaluates it like this:

Summer2022
<1 Point>+<1 Point>

The password needs to meet at least 5 points in order to be allowed. Point values are provided like this:

  1. Each banned password that’s found in a user’s password is given one point.
  2. Each remaining character that is not part of a banned password is given one point.
  3. A password must be at least five (5) points to be accepted.

In addition, you have to keep in mind Microsoft automatically runs the custom list through both substitution:

SuMMer, Summ3r and $ummer are all counted as “summer“.

And through fuzzing. Meaning your Summera, aSummer, Sumemer are all counted as “summer“.

Your own name is in addition counted as a banned word automatically. This would mean if I changed my password to:

SummerJames2022

The password would be rejected, as it’s only 3 points. You can read more here.

Training your users to set proper passwords is a requirement, and transparancy about your word list (at least partially) is key to a good implementation. Remember the error messages users get are obtuse, meaning communication and training is even more important than usual.

Thank you for reading!
I’m going to try writing more often on the blog, it’s just been really stressful at work. Thank you for your patience!

Would you like to read more?