FalconFriday — Password Spraying with(out) MDI—0xFF10
In this FalconFriday, we have two queries that allow you to detect password spraying attacks. We provide one variant for Microsoft Defender for Endpoint (MDE) and one for Microsoft Defender for Identity (MDI). In contrast to the detection that comes built-in with MDI, our MDI rule allows you to tune the sensitivity to your needs.

TL;DR for blue teams: If you don’t have MDI implemented, you can use the MDE variant to detect password spraying using server/endpoint logs. If you do have MDI implemented, you can use this rule to adjust the sensitivity of password spraying detection with MDI. Even if you don’t have MDE and MDI, you can easily adjust this rule to detect password spraying with just the raw SecurityEvents.

TL;DR for red teams: Password spraying can be easily detected by any decent security monitoring solution. If you need to do it anyway, make sure you perform the spray from a burnable host.

Detection logic

Detecting password spraying is of course conceptually very easy: you need to identify a (large) number of failed logons coming from a small number of hosts. In the Microsoft security stack, the four main locations where you can get data for failed logon attempts are:

  • Microsoft Defender for Endpoint — DeviceLogonEvents.
  • Microsoft Defender for Identity — IdentityLogonEvents.
  • Windows Security Event Logs — Event 4625.
  • Azure AD Logs — SigninLogs.

The practical problem for detecting password spraying is the fact that you can’t only look at the absolute number of failed logons from a single source. A service running in your environment might use delegated authentication, and users inevitable enter a wrong password sometimes, so a popular service might trigger a large number of failed logons for a large number of different accounts, coming from the same server. This is obviously a false positive. Another case of a false positive might be an incorrectly configured application, trying to authenticate with incorrect credentials. This, for example, might happen when you forget to update the password of that service account in this application.

To account for those common reasons for false positives, we will use the following criteria to identify password spraying.

  • The number of unique accounts with failed authentication attempts is greater than some tunable threshold (thresholdForUniqueFailedAccounts). This is mostly to eliminate false positives due to some misconfigured service accounts which generate a large number of failed authentication attempts.
  • The absolute number of failed logons originating from a source IP is larger by a tunable factor (ratioSuccessFailedLogons) than the number of successful logons. This is to filter out servers that perform a large number of authentication requests and hence will have a large absolute number of failed logons as a consequence.
  • The number of failed logons per account is on average less than some tunable factor (upperBoundOfFailedLogonsPerAccount). To prevent account lockout, password spraying just tries one or few passwords per account. Anything which has on average more than a few tries (1–3) per account, isn’t password spraying by definition.

As you can see, you can tune these three parameters to make it work in your environment.

Microsoft Defender for Endpoint (MDE)

This version of the query allows you to detect password spraying based on the DeviceLogonEvents. The query checks for each “remote IP” if they satisfy the above three conditions and reports back if they do. Get your copy here.

Microsoft Defender for Identity (MDI)

Defender for Identity has a built-in detection for password spraying. However, in my experience this detection is a bit unpredictable. The only documentation I could find on it, seems to be this small paragraph. And it’s very unclear what it does under the hood. The built-in detection has a learning period, which seems to suggest that it does some benchmarking of “normal”. As I wasn’t too happy with it and I already had the approach using MDE, it was fairly easy to modify it to a custom MDI query. The query is basically the same, with some different field names because of differences in the schema layout. Get your copy here.

Windows Security Event Log

Based on the logic of the two queries above, it should be fairly straightforward for you to modify the queries to be based on failed logons for Windows Security Event Logs. If you’ve built it and want to share back, we’d love to get a pull request on GitHub from you. We’ll ship you a gift card or t-shirt as a gesture of appreciation!

Azure AD

In case you’re ingesting Azure AD logs in Sentinel, but don’t have MDE/MDI, you can use this default rule provided by Microsoft. This rule works on slightly different assumptions and hence will produce different results.

Tips for tuning

We’ve provided some default values for the three criteria/parameters that you can tune. However, you might want to change the values depending on peculiarities in your environment.

  • thresholdForUniqueFailedAccounts — This parameter lets you choose the threshold of the number of unique accounts that had failed logons coming from a single source. Lower is better; set this as low as possible with an acceptable number of false positives. Don’t go below +/- 5 though; if you’re still not getting a lot of false positives below 5, it’s likely there is an issue with your logs or you have no servers onboarded in MDE.
  • upperBoundOfFailedLogonsPerAccount — This parameter is an upper bound for the number of attempts per account. Any account with more failed logons than this bound is discarded. You want to set this value as high as possible. The value also depends on the lookback window. The shorter the lookback window, the smaller this value can be. A default value of 10 is reasonable, as a password spray usually doesn’t do more than 10 attempts per account per day, but that’s just my experience.
  • ratioSuccessFailedLogons — This ratio is used to determine a lower bound for the number of failed logons, based on the number of successful logons. The lower this value, the lower the number of failed logons from a source have to be before this condition to be met. To make this more tangible, assume 20 successful logons from a given source in a given period. A ratio of 0.1 means that this condition will be met if there are more than 2 failed logons from the same host in the same period. A ratio of 1 means more than 20 failed logons. A ratio of 2 means more than 40 failed logons. You want to have this ratio as low as possible. The default value of 0.5. I would be suspicious for anything below 0.2 or above 1.


In some cases I have seen a large number of false positives originating from domain controllers. The authentication request was originating from a domain controller, and was directed to another domain controller or to a server. I haven’t yet figured out why that happens, but it’s definitely not password spraying. If you see this happening, you can filter out authentication requests originating from domain controllers. You can load the list of your domain controllers as a watchlist or as an external data source.

Knowledge center

Other articles

Together. Secure. Today.

Stay in the loop and sign up to our newsletter

FalconForce realizes ambitions by working closely with its customers in a methodical manner, improving their security in the digital domain.

Energieweg 3
3542 DZ Utrecht
The Netherlands

FalconForce B.V.
[email protected]
(+31) 85 044 93 34

KVK 76682307
BTW NL860745314B01