Microsoft 365 (formerly Office 365) is Microsoft's cloud-based suite of productivity tools, which includes email, collaboration platforms, and office applications. All are integrated with Entra ID (referred to as Azure AD in this post) for identity and access management. M365’s centralized storage of organizational data, combined with its ubiquity and widespread adoption, make it a common target of threat actors.
Initial access represents the first foothold that threat actors establish within an organization's environment. In the realm of cloud computing, identity has become the new perimeter. A compromised account can set the stage for further exploitation and data exfiltration. Blue teams should remain vigilant regarding initial access techniques so they can proactively identify attackers before they cause harm.
In this blog post, the Splunk Threat Research Team begins by providing an overview of the available data sources for M365 monitoring. We then introduce six common techniques typically used during initial access against M365 tenants, explaining how to simulate them and how teams can detect them using Splunk.
The foundation of effective threat detection lies in the data sources we have available to develop analytics. Understanding the range and quality of these data sources is key for establishing a detection strategy. This section describes the relevant data sources, their differences, and how to ingest them into Splunk.
The Unified Audit Log (UAL) in M365 aggregates logs from various services, such as Exchange Online, SharePoint Onlinet, OneDrive, Microsoft Teams and Azure AD. Consolidating this data provides a centralized view of user activities across the M365 environment. To access and query these logs, teams can use the PowerShell cmdlet Search-UnifiedAuditLog. Additionally, the Management Activity API serves as another avenue to obtain these logs, providing a method to integrate with external analysis tools.
For security teams aiming to ingest M365’s UAL into Splunk, the Splunk Add-On for Microsoft Office 365 leverages the Management Activity API to facilitate the retrieval of activity audit logs.
Given that M365 relies on Azure AD for identity and access management, the Azure AD logs play a crucial role in security monitoring. Azure AD’s sign-in and audit logs feature a rich schema and detailed context. To access and analyze these logs, security teams can use the Microsoft Graph API and REST clients like the PowerShell SDK. Additionally, Azure Event Hubs facilitates integration with data streaming pipelines.
To ingest Azure AD events into Splunk, the Splunk Add-on for Microsoft Azure uses the Graph API. In parallel, the Splunk Add-on for Microsoft Cloud Services offers compatibility with Azure Event Hubs. Splunk Cloud Platform users can use the built-in Data Manager application that provides simple data onboarding.
While both the UAL and Azure AD audit logs are pivotal for security monitoring of M365, they serve different purposes and have distinct schemas. The UAL offers a broad view across various M365 services, making it an essential tool for a holistic understanding of user activities. However, it lacks some of the granular details relevant to authentication and identity management events available in the Azure AD logs.
As an example, the UAL with its "UserLoggedIn'' events offers a foundational overview of user authentication activities. However, it lacks coverage for important authentication events such as service principal, non-interactive and managed identity sign-ins. Additionally, the details provided in these events are often not extensive enough for in-depth analysis.
Image 1: UAL UserLoggedin event
In contrast, Azure AD's "Sign-in activity" event is more encompassing, covering additional distinct authentication subcategories, including service principal, non-interactive and managed identity sign-ins. This range offers the comprehensive view required to flag M365 attacks that involve stolen access tokens or the abuse of service principals and Azure resource identities.
Azure AD authentication events offer a comprehensive dataset that includes user and application information, location, device details, conditional access insights, and details on the authentication method used, indicating whether it involved single or multi-factor authentication (MFA). Additionally, Azure AD logs incorporate risk sign-in information powered by Azure AD Identity Protection, offering even more context.
Image 2: Azure AD Sign-in activity event
Understanding these and other differences is crucial for security teams to build robust detection analytics. The UAL is best suited for analytics related to the potential abuse of the different M365 services. In contrast, Azure AD logs should be the primary source for authentication and identity detection analytics. Integrating insights from both data sources can provide comprehensive visibility.
The Splunk Threat Research Team is dedicated to empowering security teams with the tools and insights needed to quickly identify and neutralize threats. In line with this mission, we crafted 30+ analytics for M365 initial access techniques, leveraging both the M365 UAL as well as the Azure AD logs. This approach guarantees that security teams using Splunk, regardless of their specific data sources, are equipped with capabilities to detect, hunt, and safeguard their M365 environments.
These analytics can be found at our site research.splunk.com, specifically within the Office 365 Account Takeover and Azure AD Account Takeover analytic stories.
In this section, we explore common initial access techniques used by attackers to breach M365 tenants. For each technique covered in this section, we provide:
In password spraying attacks, adversaries employ a few commonly used passwords against a broad array of usernames to obtain valid credentials. The deprecation of basic authentication marked a significant shift towards the use of more secure, modern authentication practices. MFA adoption rose to 37% in 2023 compared to 0.7% in 2017.
Despite these advancements, password spraying remains a prevalent threat and adversaries continue to leverage this attack vector in the wild. Furthermore, as we will explore later in this post, adversaries now employ methods that circumvent MFA controls once credentials are obtained.
The Microsoft Digital Defense Report of 2023 highlights a surge in password-based attacks on the Microsoft platform, with incidents of password spraying increasing more than tenfold. The same report documents sophisticated password spray campaigns that use a distributed network of IP addresses across various countries to evade security controls such as Azure ID Identity Protection and Smart Lockout.
Image 3: Multi-source password spray
Simulation
For simulating traditional password spraying attacks, detection engineers can use a variety of open-source tools, such as MSOLSpray, o365spray, and Go365. To simulate a distributed, multi-source spraying attack, we can leverage fireprox. Fireprox uses AWS API Gateway to create pass-through proxies that rotate the source IP address for every request. MSOLSpray natively integrates with Fireprox with the URL parameter. Finally, to populate our Azure AD lab environment with simulated users, we use BadZure.
Image 4: MSOLSpray
Telemetry Insights
Failed authentication attempts are recorded with the error code 50126, which denotes “Error validating credentials due to invalid username or password.” While the description suggests this error code can also be triggered by submitting an invalid username, our testing has not found that to be the case.
In fact, Microsoft’s documentation distinctly assigns the error code 50034, “The user account does not exist in the tenant directory,” to scenarios involving non-existent user accounts. Although this error is returned in client requests, it is not logged in the Azure AD logs. In contrast, within a Windows Active Directory setting, the Kerberos error 0x6 serves as an indicator for authentication attempts involving non-existent users.
Detection Opportunities
Azure AD Multiple Users Failing To Authenticate From IP
Security teams can leverage error code 50126 on both the UAL and Azure AD logs to identify a traditional password spraying attack where a high number of users fail to authenticate from one single source IP in a short period of time.
`azuread` category=SignInLogs properties.status.errorCode=50126 properties.authenticationDetails{}.succeeded=false | rename properties.* as * | bucket span=5m _time | stats dc(userPrincipalName) AS unique_accounts values(userPrincipalName) as userPrincipalName by _time, ipAddress | where unique_accounts > 30
Azure AD Multi-Source Failed Authentications Spike
Detecting a multi-source distributed password spray present, requires a different strategy. Our approach hinges on identifying authentication spikes within a short period of time that exhibit specific characteristics. This analytic calculates key metrics such as the:
By customizing the thresholds for these metrics, we can hunt for patterns that deviate from normal behavior.
`azuread` category=SignInLogs properties.status.errorCode=50126 properties.authenticationDetails{}.succeeded=false | rename properties.* as * | bucket span=5m _time | eval uniqueIPUserCombo = src_ip . "-" . user | stats dc(uniqueIPUserCombo) as uniqueIpUserCombinations, dc(user) as uniqueUsers, dc(src_ip) as uniqueIPs, dc(location.countryOrRegion) as uniqueCountries values(user) as users, values(src_ip) as ips, values(user_agent) as user_agents, values(location.countryOrRegion) as countries by _time | where uniqueIpUserCombinations > 20 AND uniqueUsers > 20 AND uniqueIPs > 20
To review UAL versions of these detections, go to O365 Multiple Users Failing To Authenticate From Ip and O365 Multi-Source Failed Authentications Spike.
In M365 environments, OAuth, a protocol used for authorization, allows third-party applications to interact with organizational data. Attackers exploit this by registering malicious Azure applications and then deceiving users into granting them consent. Once attackers obtain this unauthorized consent, they can acquire an access token, enabling them to access sensitive information, read emails, and perform actions on behalf of the user. This approach notably allows them to circumvent multi-factor authentication (MFA).
In response, Microsoft implemented controls such as publisher verification and risk-based step-up consent, which significantly reduced the risk of illicit consent grant attacks. Despite these advancements, blue teams must remain vigilant to this attack vector, recognizing scenarios where attackers could bypass these controls. As an example, earlier this year, Proofpoint reported on a campaign that they identified where adversaries abused Microsoft’s “verified publisher” status to meet some of the OAuth distribution requirements. Similarly, Secureworks recently published research demonstrating their ability to spoof the verified publisher status.
Simulation
To simulate the illicit consent grant attack, there are multiple open source tools available, including PwnAuth, o365-attack-toolkit, and 365-Stealer. We will leverage 365-Stealer. First, we need to create a multi-tenant app registration, as described on their github page. With these requirements in place, we can configure and run the tool, which will provide a phishing link that can be sent to our simulated victims.
Image 5: 365Stealer
By default, the security controls previously mentioned will promptly block consent requests for recently created multi-tenant app registrations, as seen below. In order to simulate an attacker who has somehow bypassed these controls, we can disable the risk-based step-up consent using PowerShell following this guide.
Image 6: Blocked OAuth consent
With risk-based step-up disabled, the victim user will see the following screen when visiting the malicious link. In this example, the malicious application is requesting access to read and send emails on behalf of the user. Specifically, the Mail.Read, Mail.ReadWrite and Mail.Send permissions are requested.
Image 7: Illicit consent grant request
Once a victim accepts the consent, the attacker obtains an access token.
Image 8: Stolen Token
Telemetry Insights
When a user visits a malicious OAuth consent URL and encounters a consent grant prompt, the 'Consent to application' event is triggered. This event provides essential information, such as whether the consent was successful, the identity of the targeted user, the name of the application, and the requested permissions. A notable difference from the UAL is that Azure AD logs include an IP address field. However, this IP address does not represent the victim or the attacker. In our testing, we found that this IP address typically belongs to Microsoft's IP space.
The “ConsentAction.Permissions” field within “ModifiedProperties” of both data sources lists the permissions requested by the application. By extracting and analyzing this field, we can develop targeted detection analytics. In the Microsoft Graph API, there are numerous permissions, but within the context of M365, two categories are particularly significant: “Read.*” and “Files.*”.
Image 9: Consent to application log event
The details provided by the “Consent to application” event enable the creation of targeted detection analytics, focusing on specific scenarios that warrant notification. Furthermore, if the victim grants consent, three additional events are generated: “Add service principal,” “Add delegated permission grant,” and “Add app role assignment grant to user.”
Image 10: Success consent events
Detection Opportunities
O365 User Consent Blocked for Risky Application
Prevention controls not only block threats but also provide insights into the profiles of targeted users and can prompt further defensive strategies. In this context, we wrote a detection that identifies instances where M365 has blocked a user's attempt to grant consent to an application deemed risky or potentially malicious.
`o365_management_activity` Workload=AzureActiveDirectory Operation="Consent to application." ResultStatus=Failure | eval permissions =mvindex('ModifiedProperties{}.NewValue', 4) | eval reason =mvindex('ModifiedProperties{}.NewValue', 5) | search reason = "Risky application detected" | rex field=permissions "Scope: (?[^,]+)" | stats max(_time) as lastTime by Operation, user, reason, object, Scope | `security_content_ctime(lastTime)`
O365 Block User Consent For Risky Apps Disabled
In our simulations, we deliberately disabled the risk-based step-up security control. This action triggers an event under the “Update authorization policy” category. Monitoring for such events can reveal whether a persistent attacker is attempting to weaken security defenses, or if an administrator has inadvertently disabled this control.
`o365_management_activity` Workload=AzureActiveDirectory Operation="Update authorization policy." | eval index_number = if(mvfind('ModifiedProperties{}.Name', "AllowUserConsentForRiskyApps") >= 0, mvfind('ModifiedProperties{}.Name', "AllowUserConsentForRiskyApps"), -1) | search index_number >= 0 | eval AllowUserConsentForRiskyApps = mvindex('ModifiedProperties{}.NewValue',index_number) | where AllowUserConsentForRiskyApps like "%true%" | stats count min(_time) as firstTime max(_time) as lastTime by user, Operation, AllowUserConsentForRiskyApps, user_agent | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
O365 File Permission Application Consent Granted by User
Specific Graph permissions enable applications to read and send emails on behalf of the user and access files in OneDrive and SharePoint.
`o365_management_activity` Workload=AzureActiveDirectory Operation="Consent to application." ResultStatus=Success | eval admin_consent =mvindex('ModifiedProperties{}.NewValue', 0) | search admin_consent=False | eval permissions =mvindex('ModifiedProperties{}.NewValue', 4) | rex field=permissions "Scope: (?[^,]+)" | makemv delim=" " Scope | search Scope IN ("Files.Read", "Files.Read.All", "Files.ReadWrite", "Files.ReadWrite.All", "Files.ReadWrite.AppFolder") | stats max(_time) as lastTime values(Scope) by Operation, user, object, ObjectId | `security_content_ctime(lastTime)`
O365 Mail Permission Application Consent Granted by User
`o365_management_activity` Workload=AzureActiveDirectory Operation="Consent to application." ResultStatus=Success | eval admin_consent =mvindex('ModifiedProperties{}.NewValue', 0) | search admin_consent=False | eval permissions =mvindex('ModifiedProperties{}.NewValue', 4) | rex field=permissions "Scope: (?[^,]+)" | makemv delim=" " Scope | search Scope IN ("Mail.Read", "Mail.ReadBasic", "Mail.ReadWrite", "Mail.Read.Shared", "Mail.ReadWrite.Shared", "Mail.Send", "Mail.Send.Shared") | stats max(_time) as lastTime values(Scope) by Operation, user, object, ObjectId | `security_content_ctime(lastTime)`
M365 and its authentication processes are built upon the OAuth protocol, which supports various authentication flows to support different device capabilities and user experiences. While these flows offer flexibility and convenience, they also introduce new attack vectors.
One such flow, as outlined in RFC 8628, is the OAuth protocol extension known as device authorization grant, which is designed to accommodate devices that have constrained input capabilities, like smart TVs. This protocol extension enables these devices to participate in the OAuth authentication and authorization processes without requiring the user to input their credentials. Instead, the device generates a unique code and prompts the user to enter this code on a separate device, like a computer.
Image 11: Device Code Prompt
This technique grants the attacker the ability to bypass MFA and gain unauthorized access to M365 services, potentially leading to a wide range of malicious activities.
Simulation
Attackers can abuse the device authorization grant by initiating a device code authorization flow themselves to obtain a unique user code. They then deceive victims into entering this code on a legitimate Microsoft website, often under the guise of a trustworthy process or necessary action. If the victim is convinced and submits the code, the attacker can capture the resulting access token. TokenTactics is an open source tool that automates this technique.
Image 12: TokenTactics
Once our simulated victim submits the code to the Microsoft-hosted site, the attacker obtains an access token that can be used to consume M365 services.
Image 13: Stolen Token Bearer
Telemetry Insights
Unfortunately, the telemetry from the UAL falls short in providing the necessary context to effectively identify device code authentication attempts. In contrast, Azure AD's “Sign-in activity” events offer a more detailed dataset for detecting this behavior. Key to this visibility is the “authenticationProtocol” field within these events.
Image 14: Device code authentication logs
Detection Opportunities
Azure AD Device Code Authentication
Detecting device code authentication is straightforward, by searching for authentication events where the authenticationProtocol field is equal to deviceCode
`azure_monitor_aad` category=SignInLogs "properties.authenticationProtocol"=deviceCode | rename properties.* as * | stats count min(_time) as firstTime max(_time) as lastTime by user src_ip, appDisplayName, userAgent | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
A common method used to bypass push-based multifactor authentication involves attackers abusing previously stolen credentials to generate a flood of authentication requests. The hope is that the targeted user, overwhelmed or confused by the incessant prompts, will eventually approve one. In some scenarios, adversaries have taken to directly reaching out to targets via alternative communication methods, such as instant messaging or phone calls, to manipulate or coerce them into approving the fraudulent authentication requests.
Telemetry Insights
MFA fatigue can be detected by monitoring for an excess of failed MFA attempts, indicated by Azure AD's error code 500121, “Authentication failed during strong authentication request.” Leveraging this error code, security teams can identify an unusual number of failed authentications that may arise from users being bombarded with MFA prompts. The “additionalDetails” field in Azure AD logs is particularly useful, as it distinguishes between user rejections and timeouts. This granularity enables security teams to write specific detections and, in some scenarios, avoid false positives. The UAL does not provide this granularity.
Detection Opportunities
Azure AD Multiple Denied MFA Requests For User
Once again, the threshold for what constitutes a high volume can vary between organizations and should be tailored to align with normal user behavior patterns within each specific environment.
`azuread` category=SignInLogs operationName="Sign-in activity" | rename properties.* as * | search status.errorCode=500121 status.additionalDetails="MFA denied; user declined the authentication" | bucket span=10m _time | stats count min(_time) as firstTime max(_time) as lastTime by user, status.additionalDetails, appDisplayName, user_agent | where count > 9 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Azure AD Multiple Failed MFA Requests For User
`azuread` category=SignInLogs operationName="Sign-in activity" properties.status.errorCode=500121 properties.status.additionalDetails!="MFA denied; user declined the authentication" | rename properties.* as * | bucket span=10m _time | stats count min(_time) as firstTime max(_time) as lastTime by user, status.additionalDetails, appDisplayName, user_agent | where count > 9 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
In the event of credential compromise, adversaries may proceed to map out the MFA landscape of the targeted tenant. Given the complexities of conditional access policies, administrative oversights can inadvertently leave certain authentication srcways vulnerable to single-factor access. Attackers are aware of this and employ automated tools designed to probe by simulating different device types, seeking out these security gaps. Upon discovering such an oversight, they exploit these credentials to circumvent MFA protections, gaining unauthorized access.
Simulation
Tools like MFASweep and TeamFiltration automate the process of using valid credentials to authenticate to different Microsoft cloud services using different user-agents.
Image 15: MFASweep
Telemetry Insights
When these tools are executed, they generate multiple successful authentication attempts from the same user, with two notable characteristics: a variety of user agents and a range of application IDs. Typically, a user might authenticate using two or even three different user agents, corresponding to their various clients such as a browser, a mobile device, etc. However, encountering more than five distinct user agents within a short period of time is unusual and could be a sign of an adversary leveraging stolen credentials to run MFA coverage enumeration.
Detection Opportunities
O365 Multiple AppIDs and UserAgents Authentication Spike
`o365_management_activity` Workload=AzureActiveDirectory (Operation=UserLoggedIn OR Operation=UserLoginFailed) | bucket span=5m _time | stats dc(_raw) as failed_attempts dc(ApplicationId) as unique_app_ids dc(UserAgent) as unique_user_agents values(ApplicationId) values(OS) by _time user src_ip | where failed_attempts > 5 and unique_user_agents > 5 and unique_app_ids > 2
Phishing attacks have traditionally involved tricking people into visiting fake websites where they're asked to input their login details. While these kinds of attacks can compromise user credentials, MFA effectively prevents unauthorized account access. Recently though, we've seen attackers adapt and come up with new methods that can circumvent MFA controls.
In an adversary-in-the-middle (AiTM) attack, attackers also trick victims into visiting a malicious site. The difference is that the phishing site doubles as a proxy server, seamlessly forwarding the victim’s requests to the legitimate web authentication site while capturing sensitive information in transit. This setup allows attackers to intercept and access critical data exchanged during the authentication process, including credentials and session cookies. This method bypasses multifactor authentication, as the attacker gains a valid session cookie, enabling an authenticated session on the target site without additional verification.
Image 16: aiTM diagram. Source
Simulation
To simulate an AiTM attack, there are a few open source tools available like Modlishka, Muraena and Evilginx. We will leverage Evilginx, a robust and flexible phishing framework. For our testing, we used a public M365 phishlet and the splunkphish.com domain to host the attack.
Image 17: Evilginx
Evilginx reverse proxy capabilities allow the victim to complete a MFA session on the attacking domain as seen below.
Image 18: Victim completing MFA
Once authentication is completed, the user is redirected to an arbitrary page and the attacker obtains the victim’s credentials as well as session cookies. At this point, the attack is successful and the cookie can be used to consume Microsoft services on behalf of the user without the need for authentication.
Image 19: Stolen session cookie in Evilginx
Telemetry Insights
In an AiTM attack, the phishing server acts as a proxy forwarding all communications including sensitive details like unaltered passwords, MFA codes, protocol headers, and user-agents. This results in authentication log entries that appear to be legitimate, mirroring a typical user sign-in from their browser. The only giveaway is the IP address. It doesn't match the user's but belongs to the phishing server instead.
In our analysis of the UAL, we identified a pattern. When a victim completes authentication on a malicious domain, it triggers a “UserLoggedIn” event. Subsequently, when the attacker imports the stolen session cookie into their browser to access the M365 tenant, another “UserLoggedIn” event occurs. These two events will have the same SessionId but different IP addresses, assuming the phishing server and the attacker's access point are not the same.
Image 20: Generated UserLoggedIn events during an aITM attack
While Azure AD logs do not provide a “SessionId” field, we can use the non-interactive user signIn logs events to accomplish the same. Non-interactive sign-ins are performed by the browser or a desktop application on behalf of a user and don't require any interaction. When an adversary imports the stolen cookie and starts browsing the victim tenant, non-interactive sign-in events will be generated.
Detection Opportunities
While we provide a few hunting ideas, their success is heavily dependent on how the attacker operates. We encourage teams to also consider prevention controls using conditional access against AiTM attacks as described in these great resources.
O365 Concurrent Sessions From Different IPs
`o365_management_activity` Workload=AzureActiveDirectory Operation=UserLoggedIn | stats min(_time) as firstTime max(_time) as lastTime values(src_ip) as ips values(user_agent) as user_agents by Operation, user, SessionId | where mvcount(ips) > 1 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Azure AD Concurrent Sessions From Different IPs
`azuread` properties.authenticationDetails{}.succeeded=true category=NonInteractiveUserSignInLogs | rename properties.* as * | bucket span=30m _time | stats count min(_time) as firstTime max(_time) as lastTime dc(src_ip) AS unique_ips values(src_ip) as src_ip values(appDisplayName) as appDisplayName by user | where unique_ips > 1 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
The cybersecurity landscape, especially within cloud-based environments like M365, is dynamic and challenging to stay ahead of. As this blog has highlighted, adversaries techniques include bypassing security measures, like MFA. An effective detection strategy should establish visibility into identity-based attacks and maintain vigilance over initial access techniques. This blog post arms security practitioners with operational insights to identify attackers before they can inflict harm.
Stay tuned for our next post, where we'll dive into how adversaries abuse compromised M365 accounts for reconnaissance and exfiltration.
The Splunk platform removes the barriers between data and action, empowering observability, IT and security teams to ensure their organizations are secure, resilient and innovative.
Founded in 2003, Splunk is a global company — with over 7,500 employees, Splunkers have received over 1,020 patents to date and availability in 21 regions around the world — and offers an open, extensible data platform that supports shared data across any environment so that all teams in an organization can get end-to-end visibility, with context, for every interaction and business process. Build a strong data foundation with Splunk.