In an earlier article, Tony described some of the information released by Microsoft about their breach by a Russian threat actor, Midnight Blizzard. During the attack, the threat actor abused insecure administrator and OAuth configurations. This article reviews some misconfigurations and how an organization can detect them using Microsoft Sentinel.

If you want to read more about what steps the attack contained and how the threat actor was able to move to the Microsoft tenant, I highly recommend this SpecterOps blog. Microsoft is hesitant to provide details on the attack, so we don’t know all of the details. This blog goes into a possible scenario, but we cannot be sure this was the case.

Password Sprays

The initial compromise of an administrator account happened due to weak account protection. Allegedly, multifactor authentication was not in place and weak passwords were used. This is an inexcusable misconfiguration. Every tenant needs to protect all users (or as a priority their administrator accounts) against password spray attacks. This is a topic which I discuss in this article.

New Administrator Accounts

Developing their attack, the threat actor created an account with administrative access in the Microsoft tenant. It is important to monitor each assignment of an administrative role and verify that the change is expected and approved. I typically identify the following highly privileged administrative roles:

RoleDescription
Global AdministratorA Global Administrator is the highest role available. They are able to delete the tenant, view all emails and documents, and gain access to all Azure resources.
Security AdministratorA security administrator can update Conditional Access policies and elevate SYSTEM privileges on all endpoints and servers using the Live Response function.
Privileged Role AdministratorThis role can assign roles to other users. By using this role, an elevation to Global Administrator is possible.
Privileged Authentication AdministratorThese administrators can take over a Global Administrator’s account by resetting their password and MFA methods.
Application AdministratorAn Application Administrator can create new apps and update existing ones. This means they can add a new credential (secret or certificate) to any existing application with high privileges. With this attack vector, an attacker could escalate privileges to Global Administrator
Cloud Application AdministratorA Cloud Application Administrator has the same permissions as an Application Administrator, excluding access to App Proxy configurations.

By using the KQL query below, you can easily identify if such a role is assigned (either using PIM or outside of PIM). When such an assignment happens, you should check if an assignment of the highly privileged role is expected and required.

let HighlyPriviligedRoles = dynamic(["Global Administrator", "Security Administrator",  "Privileged Role Administrator", "Privileged Authentication Administrator",  "Application Administrator", "Cloud Application Administrator"]);
AuditLogs
| where TimeGenerated > ago(1d)
| where OperationName in ("Add eligible member to role in PIM completed (permanent)", "Add member to role outside of PIM (permanent)", "Add member to role in PIM completed (permanent)", "Add eligible member to role in PIM requested (permanent)")
| extend ActionExecutedBy = Identity
// Exclude actions taken by PIM.
| where ActionExecutedBy != "Azure AD PIM"
| extend assignedRole = tostring(TargetResources[0].displayName)
| extend assignedTo = tostring(TargetResources[2].displayName)
| extend AUScope = tostring(TargetResources[5].displayName)
// If a user is assigned to a group, get group name
| extend assignedRole = iif(assignedRole != "Member", assignedRole, tostring(TargetResources[3].displayName))
| extend assignedGroup = tostring(TargetResources[3].displayName)
| where assignedRole in (HighlyPriviligedRoles)
| extend AlertText = strcat("A highly priviliged role assignment has been detected. The role ", assignedRole, " has been assigned to ", assignedTo, " by ", ActionExecutedBy, ". ")

Highly Privileged Application Permissions

The main escalation point in this attack was the abuse of OAuth applications. OAuth applications are often not adequately hardened (as in this case) and are overly permissioned. There are some permissions that are identified as highly privileged and should be treated with care.

PermissionDescription
AppRoleAssignment.ReadWrite.AllAllows assignment of application permissions, without requiring additional consent.
RoleManagement.ReadWrite.DirectoryThis permission allows the app to assign administrative roles.
Sites.FullControl.AllFull control for all SharePoint sites in the environment.
Mail.ReadWrite.AllReads and updates emails in every mailbox.

If these permissions are assigned to an application, they create a large risk if the application is compromised. While there are valid reasons to use these permissions, they should be handled with care.

let HighPermissions = dynamic(["AppRoleAssignment.ReadWrite.All", "RoleManagement.ReadWrite.Directory", "Sites.FullControl.All", "Mail.ReadWrite.All"]);
let detectionTime = 1d;
AuditLogs
| where TimeGenerated > ago(detectionTime)
| where OperationName =~ "Consent to application"
| mv-apply TargetResource = TargetResources on
  (
      where TargetResource.type =~ "ServicePrincipal"
      | extend AppDisplayName = tostring(TargetResource.displayName),
               AppClientId = tostring(TargetResource.id),
               props = TargetResource.modifiedProperties
  )
| mv-apply ConsentFull = props on
  (
      where ConsentFull.displayName =~ "ConsentAction.Permissions"
  )
| mv-apply AdminConsent = props on
  (
     where AdminConsent.displayName =~ "ConsentContext.IsAdminConsent"
  )
| parse ConsentFull with * "ConsentType: " GrantConsentType ", Scope: " GrantScope1 "]" *
| where ConsentFull has_any (HighPermissions)

Some of the permissions I listed can be scoped to a set of objects. This is an important step to take as it greatly limits exposure. For example, there aren’t many applications that require full access to every mailbox and the typical need is for access to a subset of mailboxes. Restricted access to sensitive mailboxes can be achieved using RBAC for Applications. Currently, only Exchange and SharePoint have mechanisms to scope permissions. If Microsoft expands this kind of RBAC to all workloads, it will allow tenants to decrease their attack surface.

Tracking Apps Through Sign-Ins

After creating the malicious application, the attacker used the app to extract data. Service Principals with application permissions require an application secret or certificate to sign-in. These sign-ins are not listed in the Entra ID Sign-in logs for user accounts but are present in a dedicated category called ‘Service Principal Logs’. In Sentinel, the table is called ‘AADServicePrincipalSignInLogs’.

The apps typically run as a background task and are predictable, they are run on a dedicated set of servers or resources. This enables you to add monitoring on top of them. Monitoring can notify you if the application runs from a new IP address, which could be an indicator that the app is being abused. Below you can find an example of such a query. It’s just a matter of updating the first two parameters to select what app you want to monitor and from what IP ranges you expect the app to log in from.

let allowedIPRange = dynamic(["20.101.174.49"]);
let AppToMonitor = "MDATPTags";
AADServicePrincipalSignInLogs
| where ServicePrincipalName == AppToMonitor and IPAddress !in (allowedIPRange)

The Importance of Response

Creating monitoring rules is one thing, but ensuring they are responded to properly is another story. Alert Fatigue is often seen in a SOC and occurs when a SOC is so accustomed to an alert, that they don’t investigate it properly. While I have no evidence to back up my theory, I suspect this happened at Microsoft. I can’t imagine Microsoft has not deployed some of the rules described above. Even better, Microsoft Sentinel already includes rule templates covering scenarios like the assignment of highly-permissioned roles or the usage of applications to extract emails.

Microsoft has one of the largest IT organizations to take care of complex architectures and different teams. It is possible that incidents were generated, but they were incorrectly attributed to development testing.

Every SOC should regularly review the efficiency of each rule, tweak it if desired, and ensure a proper ‘Standard Operating Procedure’ is available. This ensures that there is no room for interpretation and that every SOC analyst knows how to investigate a certain incident.

Staying Ahead of It

Attacks constantly evolve and attackers target cloud-specific misconfigurations that tenants might not know about. This attack is a perfect example of how organizations struggle to keep cloud environments secure. If Microsoft can be compromised, any organization can be compromised. Fighting attacks is an ever-lasting battle. Organizations need to review their environment, identify their gaps, and ensure that systems are properly monitored.

About the Author

Thijs Lecomte

Thijs is a security consultant out of Belgium, working at The Collective, an MSSP with a Microsoft-focused Security Operations Center. His work consists out of leading the SOC team and implementing Microsoft Security solutions (such as Microsoft Sentinel and Defender) as a consultant. He is an MVP in the Security category and is a regular speaker at events and user groups. His best-known publication is as co-author of the 'Microsoft 365 Security for the IT Pro' ebook.

Leave a Reply