More and more organizations are enrolling users in Multi-Factor Authentication (henceforth referred to as MFA) wherein a secondary form of authentication takes place following a user inputting their credentials into a service to ensure a user is who they say they are. It’s an added layer of security and authentication that can help prevent compromise. But this isn’t bulletproof.
Recently a few blog posts and papers have begun to come out detailing a bypass technique known as "MFA bombing", "MFA Fatigue", "Push Notification Spamming", and many other terms, detailing high-profile threat actors such as LAPSUS$ who have abused the technique to gain access to otherwise protected areas. The technique was one we at Lares (and other red teams!) have used with overwhelming success in the past. We know it as Push Fatigue.
What is Push Fatigue?
Simply put, Push Fatigue is when a user is consistently spammed with push notifications from an MFA service requesting confirmation that a login attempt was made with their credentials. The objective with the technique is to annoy or "fatigue" the user into accepting one of the pushes to make the notifications stop. In this stage, an attacker has successfully guessed or otherwise compromised a valid set of credentials for a service and is now attempting to authenticate to the service and continue their attack path.
Wouldn’t this just annoy the user?
This was my initial thought. Wouldn’t a user who’s inundated with these messages notice that something is off? Wouldn’t they report this to their IT team so they can investigate the issue?
Unfortunately, it’s not that simple. There’s a lot of variables that come into play when this technique is performed, such as:
- The time of day the user is prompted
- The frequency of the prompts
- The type of prompt (Phone call or authenticator push)
- The security awareness training of the user
- The organization policy on reporting incidents
- The controls put in place by the organization
- How do all of these play a part?
Let’s go through each one quickly.
Time of day: An attacker is going to try and time the attack for when it most inconveniences users. Whether that be dinner time, the weekends at 9AM, 1AM on a weekday, or a holiday — the more inconvenient the time, the more likely a user will accept the prompt to make the flood stop.
Frequency of the prompts: One tip Will Bonk gave me (in addition to introducing me to the technique — you the man Will!) was to try and time prompts to occur at a fixed time increment, such as every 5 minutes or every 10 minutes. The idea here is to try and convince a user that an automated program is authenticating on the user’s behalf and is failing, so it keeps retrying! Of course, sending a new push as soon as the first one expires or gets rejected is certainly valid too.
The type of prompt: Phone calls are harder to ignore than push notifications. Spamming phone calls is more likely to elicit a reaction from the user, with the hopes of then answering and following the phone prompts to accept the notification and make the calls stop. This is especially true since users are typically conditioned with push notifications to only receive them when they themselves log into a service. If a user starts receiving push notifications when they themselves did not login to anything, it may raise more suspicion.
Security awareness training: Push Fatigue isn’t always talked about in Security Awareness training programs. Users often aren’t even aware that this is something they SHOULD be mindful of, or something that can happen to them.
Organization Incident Policy: A user may not always understand that multiple MFA prompts, even when they reject them, indicates that their account credentials have been compromised. In my personal experience performing this attack, even when a user rejected the prompts and/or reported the attempts, the password wasn’t always changed. This can sometimes be attributed to an organizations incident reporting policy as to what qualifies as an incident or not as well as actions to take as a response.
Organization Controls: Nowadays, there are different types of multi-factor authentication controls that can be used to detect or even prevent this type of attack. As an example, Microsoft is currently previewing a “number matching” feature with Office 365/Azure MFA that will display a number that the end user has to enter into the prompt. Other third-party authentication solutions will send a four to six-digit PIN code to the user’s mobile device that must be entered. These of course all have their ups and downs, but each one plays a unique role in helping prevent Push Fatigue.
There’s some immediate steps that can be taken to help prevent push fatigue. The first and most immediate? Do not use push-based notifications or calls. There are multiple other options and solutions that are available that do not rely on a user tapping "yes" or "no" to allow an authentication attempt through. As previously mentioned, requiring a four-to-six digit PIN code is an option for some MFA solutions, and Microsoft themselves is previewing a number matching feature for Office 365 MFA. For more information, please refer to the following documentation for Microsoft number matching: https://docs.microsoft.com/en-us/azure/active-directory/authentication/how-to-mfa-number-match
Another immediate step that can be taken is in regard to detection. The MITRE ATT&CK mapping and relevant KQL for a possible scenario are below:
The above was generated using the Mitre ATT&CK Navigator.
//Detect when a user denies MFA several times within a single sign in attempt and then completes MFA. //This could be a sign of someone trying to spam your users with MFA prompts until they accept. //Select your threshold of how many times a user denies MFA before accepting let threshold=2; SigninLogs | project TimeGenerated, AuthenticationRequirement, AuthenticationDetails, UserPrincipalName, CorrelationId //Expand and count all the denied challenges and then return CorrelationId's where the MFA denied count is greater or equal to your threshold | where ['Result Types'] has_any ("MFA denied; user declined the authentication","MFA denied; user did not respond to mobile app notification") | summarize ['Denied MFA Count']=count()by ['Result Types'], CorrelationId, UserPrincipalName | where ['Denied MFA Count'] >= threshold
If you’d like to learn more about how to optomize your mitigating controls, test them for defficiencies, or simply stress test them in a real-world environment, please contact us today.
Alex is an Information Systems Security Graduate and knew he would end up in a penetration testing or Red Team role ever since the concepts were introduced to him. He has experience with a variety of assessments and adversary scenarios. When he isn’t in someone else’s network, he enjoys learning and preparing for the next engagement by researching the latest and greatest techniques and loves nothing more than a practical attack that he can put to good use. Outside of security, he enjoys traveling and restoring old cars.